Ruby:从实例调用类方法


347

在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吗?似乎应该有。

Answers:


563

在实例方法内部,您可以调用而不是引用类的文字名称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

输出:

上课方法:Foo
实例方法:Foo

7
我想在ruby中看到一些快捷方式,以从实例中调用类方法。即::> some_class_method而不是self.class.some_class_method
2011年

7
尽管这是正确的答案,但可耻的是,“ self.class”比类名“ Truck”更具键入性且不易阅读。噢....
马特·康诺利

22
@MattConnolly,它是相对的,如果您的班级名称是SalesforceSyncJob较短的;)
drewish

29
@MattConnolly,self.class如果您正好重命名该类,也可以使用它来进行搜索/替换。
Gus Shortz

8
@GusShortz是的。另外,如果有子类,则self.class会更好地工作。
Matt Connolly13年

183

使用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" 

58
这似乎是对已接受答案的回应,而不是对问题的答案。
zhon 2013年

16
@zohn-是的,但是在考虑使用什么时,这仍然是有用的上下文。
马特·桑德斯

1
在这种情况下,@ MattSanders仅使用注释。
nandilugio '16

1
@hlcs self.class对保留继承是正确的。即使make1()是在中定义的Truck,它仍引用BigTruck的class方法。
Kaiser Shahid

Class_name.method_name工作完美
Houda M

14

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

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

make不应是实例方法。它是一种工厂,应该绑定到类而不是实例上
phoet 2011年

6
@phoet品牌词表示汽车的品牌(例如,丰田,宝马等)englishforums.com/English/AMakeOfCar/crcjb/post.htm。命名基于用户要求
Harish Shetty

8

如果您有权访问委托方法,则可以执行以下操作:

[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所有不会将状态更改为类和实例的内容,因为您将开始遇到奇怪的名称冲突问题。请谨慎执行此操作,并且只有在您检查完其他所有内容之后才进行压缩。



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

2
我不同意这default_make应该是一个实例方法。即使对于这些示例来说更简单,但这也不是正确的语义-默认值是类的产品,而不是属于该类的对象。
彼得

1
@Peter您想用简单的方式解释一下吗?我正在学习Ruby,而Maha的答案对我来说似乎很完美。
马伦·TB

1
@ MarlenT.B。回想一下,我不确定这里有太多的东西要学习-我只是在争论放置该方法的最佳位置在哪里,而我不再像以往那样强烈地购买自己的论点!:)
彼得

2
我也不同意。某物是否为类方法与“效用”无关。关于该方法在概念上适用于该类还是该类的对象。例如,每辆卡车都有不同的序列号,因此serial_number是一个实例方法(具有相应的实例变量)。在另一个vehicle_type(返回“ truck”)上,应该使用类方法,因为这是所有卡车(而不是特定卡车)的财产
Vish 2013年

3

多一个:

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

1

这是一种有关如何实现_class适用self.class于这种情况的方法的方法。注意:请勿在生产代码中使用此代码,这是出于利益考虑:)

来自:您可以在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提交补丁:)


-6

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

class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.