首先,class << foo
语法打开了 foo
的单例类(eigenclass)。这使您能够专门为在该特定对象上调用的方法定制行为。
a = 'foo'
class << a
def inspect
'"bar"'
end
end
a.inspect # => "bar"
a = 'foo' # new object, new singleton class
a.inspect # => "foo"
现在来回答问题:class << self
打开了self
的单例类,这样方法就可以被重新定义为当前的self
对象(在类或模块主体内部是类或模块本身)。通常,这用于定义类/模块("静态")方法:class String
class << self
def value_of obj
obj.to_s
end
end
end
String.value_of 42 # => "42"
这也可以用缩写方式表示:
class String
def self.value_of obj
obj.to_s
end
end
甚至可以更短:
def String.value_of obj
obj.to_s
end
在函数定义内部,self
指的是被调用该函数的对象。在这种情况下,class << self
打开了该对象的单例类;其中一个用途是实现一个简单的状态机。class StateMachineExample
def process obj
process_hook obj
end
private
def process_state_1 obj
# ...
class << self
alias process_hook process_state_2
end
end
def process_state_2 obj
# ...
class << self
alias process_hook process_state_1
end
end
# Set up initial state
alias process_hook process_state_1
end
所以,在上面的示例中,每个StateMachineExample
实例都将process_hook
别名为process_state_1
,但请注意,在后者中,它可以重新定义process_hook
(仅对self
有效,不影响其他StateMachineExample
实例),以便变为process_state_2
。因此,每当调用者调用process
方法(调用可重新定义的process_hook
)时,行为会根据所处状态而发生变化。
class << self
的方式,用于创建类/模块方法。我可能会进一步扩展关于class << self
的使用,因为那是一个更加惯用的用法。 - C. K. Younga
的singleton_class
时,会感到困惑,因为在更改inspect
之后,a
的类是String
类的一个唯一变体。如果更改单例String
类,将影响所有其他String
实例,这更加奇怪的是,如果稍后重新打开String
以重新定义inspect
,则a
仍将拾取新更改。 - Old Proclass <<self
是否比仅仅是在块作用域内将 self
的值设置为单例类更有含义? - Cary Swoveland我找到了一份关于 class << self
,Eigenclass
和不同类型方法的超简单解释。
Ruby 中有三种可以应用于类的方法:
实例方法和类方法在其他编程语言中都有相似的概念。
class Foo
def an_instance_method
puts "I am an instance method"
end
def self.a_class_method
puts "I am a class method"
end
end
foo = Foo.new
def foo.a_singleton_method
puts "I am a singletone method"
end
访问Eigenclass
(包括单例方法)的另一种方式是使用以下语法(class <<
):
foo = Foo.new
class << foo
def a_singleton_method
puts "I am a singleton method"
end
end
现在,您可以在此上下文中为self
定义一个单例方法,该方法就是类本身Foo
:
class Foo
class << self
def a_singleton_and_class_method
puts "I am a singleton method for self and a class method for Foo"
end
end
end
foo.singleton_class.instance_methods(false)
来检查。 - Damon Yuanclass Zen
end
z1 = Zen.new
z2 = Zen.new
class << z1
def say_hello
puts "Hello!"
end
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
在上面的例子中,class << z1
将当前的self指向z1对象的元类;然后在元类中定义了say_hello方法。类也是对象(内置类Class的实例)。类方法无非就是与类对象相关联的单例方法。class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
所有对象都可能有元类,这意味着类也可以有元类。在上面的例子中,class << self 修改了 self,使其指向 Zabuton 类的元类。当定义一个没有明确接收者(方法将被定义的类/对象)的方法时,它会隐式地在当前范围内定义,也就是self的当前值。因此,stuff方法在Zabuton类的元类中定义。以上例子只是定义类方法的另一种方式。个人认为,最好使用def self.my_new_clas_method语法来定义类方法,因为它使代码更易于理解。以上示例是为了让我们了解当我们遇到class << self语法时发生了什么。
更多信息请参见有关Ruby类的此文章。
class << self
,我真的不知道他为什么要这样做。) - MDickten@count = 0
变量(在任何方法之外)。有两种访问它的方式:def self.count; @count; end
或者 class << self; attr_accessor :count; end
。在初始化方法中:self.class.count += 1
。在类外部:puts "@count=#{SomeClass.count}"
。更复杂的例子可以在 https://pragprog.com/titles/ruby5/programming-ruby-3-2-5th-edition/ 中找到。 - undefined@@count
会更容易。我见过最常见的用法是定义类方法。他们使用class << self
的技巧将self更改为类的单例类,然后使用简单的def
(def m1
,def m2
,...)在单例类中定义单例方法(通常称为类方法)。 - undefinedclass Hi
self #=> Hi
class << self #same as 'class << Hi'
self #=> #<Class:Hi>
self == Hi.singleton_class #=> true
end
end
[在其块的上下文中,它使得 self == thing.singleton_class
].
hi = String.new
def hi.a
end
hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true
hi
对象从其#singleton_class.instance_methods
继承它的#methods
,然后再从其#class.instance_methods
继承。
这里我们给了hi
的singleton类实例方法:a
。也可以使用class << hi来完成同样的操作。
hi
的#singleton_class
拥有所有hi
的#class
的实例方法,并且可能还有一些其他的(:a
在此)。
[thing的实例方法的#class和#singleton_class可以直接应用于thing。当Ruby看到thing.a时,它首先查找thing.singleton_class.instance_methods中的:a方法定义,然后在thing.class.instance_methods中查找]
顺便说一下-他们称对象的singleton类== 元类 == eigenclass。
单例方法是仅为单个对象定义的方法。
例如:
class SomeClass
class << self
def test
end
end
end
test_obj = SomeClass.new
def test_obj.test_2
end
class << test_obj
def test_3
end
end
puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods
SomeClass的单例方法
测试
test_obj的单例方法
测试_2
测试_3
rb_define_singleton_method
foo = Object.new
def foo.hello
'hello'
end
foo.hello
==>"hello"
foo.methods
def foo.self
self
end
foo.self
只是foo对象。
尝试看看如果你从其他对象(如Class和Module)中创建foo会发生什么。所有答案的示例都很好玩,但您必须使用不同的想法或概念来真正理解代码编写方式背后发生的事情。所以现在您有很多术语可以去查看。
Singleton、Class、Module、self、Object和Eigenclass都被提出过,但Ruby不会以这种方式命名对象模型。更像元类(Metaclass)。 Richard或__why在这里向您展示了这个想法。 http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html 如果这让你震惊了,那么尝试在搜索中查找Ruby对象模型。 我知道有两个YouTube视频是Dave Thomas和Peter Cooper制作的。他们也试图解释这个概念。Dave花了很长时间才明白,所以不要担心。 我还在努力理解它。否则我为什么会在这里呢? 感谢您的问题。 此外,请查看标准库。它有一个Singleton模块,这只是一个FYI。
这很不错。 https://www.youtube.com/watch?v=i4uiyWA8eFk