2010-03-27 148 views
282

调用类的方法在Ruby中,你怎么骂从该类的实例中的一个类的方法?假设我有红宝石:从实例

class Truck 
    def self.default_make 
    # Class method. 
    "mac" 
    end 

    def initialize 
    # Instance method. 
    Truck.default_make # gets the default via the class's method. 
    # But: I wish to avoid mentioning Truck. Seems I'm repeating myself. 
    end 
end 

Truck.default_make检索默认值。但是有没有一种方式说这个,而不提Truck?似乎应该有。

回答

459

而不是指类的文字名称,实例方法中,你可以叫self.class.whatever

class Foo 
    def self.some_class_method 
     puts self 
    end 

    def some_instance_method 
     self.class.some_class_method 
    end 
end 

print "Class method: " 
Foo.some_class_method 

print "Instance method: " 
Foo.new.some_instance_method 

输出:

 
Class method: Foo 
Instance method: Foo 
+5

我想看到一些ruby中的快捷方式来调用一个实例的类方法。即:> some_class_method,而不是self.class.some_class_method – phoet 2011-12-28 11:22:57

+7

,虽然这是正确的答案,但很遗憾“self.class”比班级名称“Truck”更易打字并且不易读。哦,好吧...... – 2012-01-11 11:18:38

+14

@MattConnolly,它是相对的,如果你的类名是'SalesforceSyncJob',那么它就更短了;) – drewish 2013-02-27 21:00:40

5

你正在做的是正确的方式。类方法(类似于C++或Java中的“静态”方法)不是实例的一部分,所以它们必须直接引用。

关于这一点,在你的例子你会得到更好的服务使得“default_make”一个普通的方法:

#!/usr/bin/ruby 

class Truck 
    def default_make 
     # Class method. 
     "mac" 
    end 

    def initialize 
     # Instance method. 
     puts default_make # gets the default via the class's method. 
    end 
end 

myTruck = Truck.new() 

类方法是使用该类的实用型功能更加有用。例如:

#!/usr/bin/ruby 

class Truck 
    attr_accessor :make 

    def default_make 
     # Class method. 
     "mac" 
    end 

    def self.buildTrucks(make, count) 
     truckArray = [] 

     (1..count).each do 
      truckArray << Truck.new(make) 
     end 

     return truckArray 
    end 

    def initialize(make = nil) 
     if(make == nil) 
      @make = default_make() 
     else 
      @make = make 
     end 
    end 
end 

myTrucks = Truck.buildTrucks("Yotota", 4) 

myTrucks.each do |truck| 
    puts truck.make 
end 
+1

我不同意'default_make'应该是一个实例方法。即使这些示例更简单,它也不是正确的语义 - 默认值是类的产品,而不是属于该类的对象。 – Peter 2010-03-27 06:26:13

+1

@Peter你会不会更简单地解释一下?我只是在学习Ruby,而Maha的答案对我来说似乎很完美。 – 2012-03-26 03:04:06

+1

@ MarlenT.B。回头看,我不确定这里有太多可以学习的东西 - 我只是在争论最好的地方放置这个方法,而且我不再强烈地支持我自己的观点! :) – Peter 2012-03-29 06:57:50

6

访问类方法的实例方法中,执行以下操作:

self.class.default_make 

这里是你的问题的替代解决方案:

class Truck 

    attr_accessor :make, :year 

    def self.default_make 
    "Toyota" 
    end 

    def make 
    @make || self.class.default_make 
    end 

    def initialize(make=nil, year=nil) 
    self.year, self.make = year, make 
    end 
end 

现在让我们使用我们的类:

t = Truck.new("Honda", 2000) 
t.make 
# => "Honda" 
t.year 
# => "2000" 

t = Truck.new 
t.make 
# => "Toyota" 
t.year 
# => nil 
+0

make不应该是一个实例方法。它更像是一种工厂,应该被绑定到班级而不是实例上 – phoet 2011-12-28 11:21:30

+4

@phoet make word表示汽车的制造(如在丰田,宝马等)http://www.englishforums.com/English /AMakeOfCar/crcjb/post.htm。命名是基于用户的要求 – 2011-12-28 20:56:42

156

使用self.class.blah是不一样的使用ClassName.blah,当涉及到继承。

class Truck 
    def self.default_make 
    "mac" 
    end 

    def make1 
    self.class.default_make 
    end 

    def make2 
    Truck.default_make 
    end 
end 


class BigTruck < Truck 
    def self.default_make 
    "bigmac" 
    end 
end 

ruby-1.9.3-p0 :021 > b=BigTruck.new 
=> #<BigTruck:0x0000000307f348> 
ruby-1.9.3-p0 :022 > b.make1 
=> "bigmac" 
ruby-1.9.3-p0 :023 > b.make2 
=> "mac" 
+52

这似乎是对接受答案的回应,而不是对问题的回答。 – zhon 2013-12-07 17:34:10

+12

@zohn - true,但在考虑使用什么时,这仍然是有用的上下文。 – 2016-01-19 07:34:34

+0

@MattSanders只是在这些情况下使用评论。 – nandinga 2016-08-03 21:01:58

5

如果您有机会获得委托方法,你可以这样做:

[20] pry(main)> class Foo 
[20] pry(main)* def self.bar 
[20] pry(main)*  "foo bar" 
[20] pry(main)* end 
[20] pry(main)* delegate :bar, to: 'self.class' 
[20] pry(main)* end 
=> [:bar] 
[21] pry(main)> Foo.new.bar 
=> "foo bar" 
[22] pry(main)> Foo.bar 
=> "foo bar" 

或者,也可能更清洁,如果你有更多的,那么你要委托类&实例的方法或两个:

[1] pry(main)> class Foo 
[1] pry(main)* module AvailableToClassAndInstance 
[1] pry(main)*  def bar 
[1] pry(main)*  "foo bar" 
[1] pry(main)*  end 
[1] pry(main)* end 
[1] pry(main)* include AvailableToClassAndInstance 
[1] pry(main)* extend AvailableToClassAndInstance 
[1] pry(main)* end 
=> Foo 
[2] pry(main)> Foo.new.bar 
=> "foo bar" 
[3] pry(main)> Foo.bar 
=> "foo bar" 

一个忠告:

不要只是随机delegate所有不会改变状态的类和实例,因为你会开始遇到奇怪的名称冲突问题。谨慎地做到这一点,只有在你没有检查任何东西后才会被压扁。

1

下面介绍如何实施_class方法,该方法对self.class适用于这种情况。注意:不要在生产代码中使用此,这是利益着想:)

来源:Can you eval code in the context of a caller in Ruby?http://rubychallenger.blogspot.com.au/2011/07/caller-binding.html

# Rabid monkey-patch for Object 
require 'continuation' if RUBY_VERSION >= '1.9.0' 
class Object 
    def __; eval 'self.class', caller_binding; end 
    alias :_class :__ 
    def caller_binding 
    cc = nil; count = 0 
    set_trace_func lambda { |event, file, lineno, id, binding, klass| 
     if count == 2 
     set_trace_func nil 
     cc.call binding 
     elsif event == "return" 
     count += 1 
     end 
    } 
    return callcc { |cont| cc = cont } 
    end 
end 

# Now we have awesome 
def Tiger 
    def roar 
    # self.class.roar 
    __.roar 
    # or, even 
    _class.roar 
    end 
    def self.roar 
    # TODO: tigerness 
    end 
end 

也许正确的答案是提交补丁的Ruby :)

2

还有一个:

class Truck 
    def self.default_make 
    "mac" 
    end 

    attr_reader :make 

    private define_method :default_make, &method(:default_make) 

    def initialize(make = default_make) 
    @make = make 
    end 
end 

puts Truck.new.make # => mac 
+0

Ruby版本2.1 – Alexey 2014-06-17 20:35:37

-6

类似你的问题,你可以使用:

class Truck 
    def default_make 
    # Do something 
    end 

    def initialize 
    super 
    self.default_make 
    end 
end