我有以下代码:
class MyClass
module MyModule
class << self
attr_accessor :first_name
def myfunction
MyModule.first_name = "Nathan"
end
end
end
end
当我像这样调用方法myfunction
时,它可以正常工作:
> me = MyClass::MyModule.myfunction
=> "Nathan"
> me
=> "Nathan"
但是,如果我删除class << self
并向self.
添加myfunction
前缀,则无效。
例如:
class MyClass
module MyModule
attr_accessor :first_name
def self.myfunction
MyModule.first_name = "Nathan"
end
end
end
> me = MyClass::MyModule.myfunction
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module
我正在尝试了解class << self
方法。我认为这是一种向其中的所有方法添加self.
前缀的方法,但如果这是真的,为什么不删除它并为每个方法添加self.
前缀?
提前感谢您的帮助。
答案 0 :(得分:7)
这是因为attr_accessor :first_name
也被class << self
包裹。
要按照您的建议进行操作,您可以像mattr_accessor
那样使用:
require 'active_support'
class MyClass
module MyModule
mattr_accessor :first_name
def self.myfunction
MyModule.first_name = "Nathan"
end
end
end
答案 1 :(得分:4)
为了更好地了解如何实现您的目标,请查看以下示例:
module PrintingModule
def self.included(object)
object.extend(ClassMethods)
end
module ClassMethods
def class_method_of_class
puts "I am class #{self.name}"
end
end
def instance_method_of_class
puts "My name is: #{@name}"
end
class << self
def static_module_method
puts "Printer version 1.0"
end
end
end
class SomeObject
include PrintingModule
def initialize(name)
@name = name
end
end
object = SomeObject.new("Something")
object.instance_method_of_class
SomeObject.class_method_of_class
PrintingModule.static_module_method
我希望现在更清楚,请注意这只是一种可能的方式(还有其他方式)
<强>更新强> 我会尝试更具体。当你在模块上定义instance / singleton方法时,你真正在做的是你定义了包含该模块的类的实例方法,另一方面,在模块上定义的类方法将成为该模块的类方法。第二个想知道是attr_accessor为给定参数的getter和setter创建实例方法。
现在回答你问题的一部分,在第一个例子中,你将在模块的类上创建3个类方法。在第二个方法中,您正在创建一个类方法,您尝试访问另一个类方法(setter),但是您的getter和setter被定义为实例方法=它们将成为包含您的模块的类方法的实例,您无法以这种方式找到他们=你无法访问你的getter和setter。 至于自我的解释,我不是那么熟练,但据我所知,当你使用“class&lt;&lt; self”时,你正在打开对象的本征类(每个对象都有它自己的任何一个)(注意)您定义实例方法的类,模块或类实例当然也是对象。 Ruby中对象的类方法=对象本征类的实例方法。所以你可以这样做:
text = "something"
class << text
def say_hi
puts "Hi!"
end
end
text.say_hi
当您创建类的实例(该示例中为String)时,该实例将获得它自己的唯一匿名类,该类是该类的子类。在该示例中,您已在String类的匿名子类的本征类上定义了实例方法。因此,您可以在文本对象上使用方法“say_hi”,但不能在String类上使用。所以“class&lt;&lt; self”正在打开那些本征类。
另一方面,单独的“self”只代表当前上下文中的一个对象,在某些情况下(例如你的)也是如此。对于self.included方法,它只是一个回调方法,当模块包含在具有表示对象的参数(此处为类SomeObject)的类中时,将调用该方法。
我希望我至少回答了你的部分问题。 更多信息: Difference between 'self.method_name' and 'class << self' in Ruby