Ruby:从实例调用类方法
Posted
技术标签:
【中文标题】Ruby:从实例调用类方法【英文标题】:Ruby: Calling class method from instance 【发布时间】:2011-02-01 10:32:21 【问题描述】:在 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
就这么说?好像应该有。
【问题讨论】:
【参考方案1】:而不是引用类的字面名称,在实例方法中你可以直接调用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【讨论】:
我想在 ruby 中看到一些从实例调用类方法的快捷方式。即 :>some_class_method 而不是 self.class.some_class_method 虽然这是正确的答案,但遗憾的是,“self.class”比类名“Truck”更容易打字,更不容易阅读。哦,好吧.... @MattConnolly,它是相对的,如果你的类名是SalesforceSyncJob
,那么它会更短;)
@MattConnolly,也使用self.class
,如果您碰巧重命名了类,则无需搜索/替换。
@GusShortz 是真的。此外,如果有子类,self.class 效果会更好。【参考方案2】:
在继承方面,使用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"
【讨论】:
这似乎是对已接受答案的回应,而不是对问题的回答。 @zohn - 是的,但在考虑使用什么时,这仍然是有用的上下文。 @MattSanders 只是在这些情况下使用评论。 @hlcsself.class
保留继承是正确的。即使make1()
是在Truck
中定义的,它也引用了BigTruck
的类方法。【参考方案3】:
要访问实例方法中的类方法,请执行以下操作:
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 品牌词表示汽车的品牌(如丰田、宝马等)englishforums.com/English/AMakeOfCar/crcjb/post.htm。命名是基于用户的要求【参考方案4】:如果您有权访问委托方法,则可以这样做:
[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】:self.class.default_make
【讨论】:
【参考方案6】:你做对了。类方法(类似于 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
【讨论】:
我不同意default_make
应该是一个实例方法。即使这些示例更简单,它也不是正确的语义 - 默认是类的产品,而不是属于该类的对象。
@Peter 您愿意用更简单的术语解释一下吗?我只是在学习 Ruby,Maha 的答案对我来说似乎很完美。
@MarlenT.B.回想起来,我不确定这里有太多要学习的东西——我只是在争论放置该方法的最佳位置,而且我不再那么强烈地相信自己的论点了! :)
我也不同意。某物是否是类方法与“效用”无关。它是关于该方法在概念上是否适用于类或该类的对象。例如,每辆卡车都有不同的序列号,因此 serial_number 是一个实例方法(具有相应的实例变量)。另一方面,vehicle_type(返回“卡车”)应该是一个类方法,因为这是所有卡车的属性,而不是特定的卡车【参考方案7】:
还有一个:
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
【讨论】:
【参考方案8】:这是一种关于如何实现_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 提交补丁 :)
【讨论】:
【参考方案9】:类似你的问题,你可以使用:
class Truck
def default_make
# Do something
end
def initialize
super
self.default_make
end
end
【讨论】:
以上是关于Ruby:从实例调用类方法的主要内容,如果未能解决你的问题,请参考以下文章