类<< Ruby中的自成语


873

class << selfRuby中做什么?


35
Yehuda Katz撰写了一篇有关该主题的非常不错的文章:yehudakatz.com/2009/11/15/…Yugui
Andrei,

3
另一个超好听的文章在这里:integralist.co.uk/posts/eigenclass.html
萨满Mohamadi

2
我正在模块内部看到它,这是否有所不同?github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken '16

@FullDecent并没有什么不同,因为Ruby中的所有内容都是一个包含模块和类的对象。
亚伦

Answers:


912

首先,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的singleton类,以便可以为当前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_hookself仅用于(不影响其他StateMachineExample实例))process_state_2。因此,每次调用者调用该process方法(调用redefinable process_hook)时,行为都会根据其所处的状态而变化。


22
@Jörg:+1进行编辑(我希望SO提供支持编辑的功能;哦)。确实,这是class << self创建类/模块方法的更常见用法。我可能会扩展对的使用class << self,因为这是更惯用的用法。
克里斯·杰斯特·杨

4
GSUB( “eigenclass”, “单例类”),看到即将到来的方法!redmine.ruby-lang.org/repositories/revision/1?rev=27022
马克-安德烈·Lafortune

4
这真是混乱指asingleton_classa的类(转换后inspect)是一个独特的变种String类。如果要更改单例String类,它将影响所有其他String实例。仍然很奇怪的是,如果您以后重新打开String以重新定义,inspect那么a仍然会选择新的更改。
旧版专业版

1
@OldPro我仍然更喜欢eigenclass这个名字,就像(我相信)Matz一样。但是,我想不能取悦所有人。
克里斯·杰斯特·杨

5
我发现表达“打开对象的单例类”(我已经读过很多次了)含糊不清。据我所知,即使我们都对它的含义有所了解,Ruby文档中也没有“打开”定义的类的方法。在块的作用域内,是否class << self等于的值self等于单例类?
卡里·斯沃夫兰

34

我发现了大约一个超级简单的解释class << selfEigenclass以及不同类型的方法。

在Ruby中,可以将三种类型的方法应用于类:

  1. 实例方法
  2. 单例方法
  3. 类方法

实例方法和类方法几乎与其他编程语言中的同名方法相似。

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

4
实际上,Singleton方法和Class方法是相同的,它们都存在于singleton类中。您可以foo.singleton_class.instance_methods(false)用来检查。
袁咏仪

22

通常,实例方法是全局方法。这意味着它们在定义它们的类的所有实例中都可用。相反,单例方法是在单个对象上实现的。

Ruby将方法存储在类中,并且所有方法都必须与一个类相关联。定义单例方法的对象不是类(它是类的实例)。如果只有类可以存储方法,那么对象如何存储单例方法?创建单例方法时,Ruby会自动创建一个匿名类来存储该方法。这些匿名类称为元类,也称为单例类或本征类。单例方法与元类相关联,而该元类又与定义了单例方法的对象相关联。

如果在单个对象中定义了多个单例方法,则它们都将存储在同一元类中。

class 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'…

在上面的示例中,类<< z1将当前的self更改为指向z1对象的元类;然后,它在元类中定义say_hello方法。

类也是对象(称为Class的内置类的实例)。类方法只不过是与类对象关联的单例方法。

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end

所有对象都可以具有元类。这意味着类也可以具有元类。在上面的示例中,类<< self修改了self,因此它指向Zabuton类的元类。如果在没有显式接收方的情况下定义方法(将在其上定义方法的类/对象),则会在当前范围(即self的当前值)内隐式定义该方法。因此,填充方法在Zabuton类的元类中定义。上面的示例只是定义类方法的另一种方法。恕我直言,最好使用def self.my_new_clas_method语法定义类方法,因为它使代码更易于理解。包含了上面的示例,因此我们了解了遇到类<< self语法时发生的情况。

这篇关于Ruby Classes的文章中可以找到更多信息。


15

什么类<<事情做什么:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end

[它 self == thing.singleton_class 在其块的上下文中进行]


什么是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对象继承其#methods从它的#singleton_class.instance_methods,然后从它的#class.instance_methods
在这里,我们给hi单独的类实例的方法:a。可以用类<< hi代替。
hi#singleton_class拥有所有实例方法hi#class有,可能还有一些更多(:a在这里)。

事情的的[实例方法 #class ,并 #singleton_class 可以直接应用到的事情。当ruby看到thing.a时,它首先在thing.singleton_class.instance_methods中寻找:方法定义,然后在thing.class.instance_methods中寻找]


顺便说一句-他们称呼对象的单例类 == 元类 ==本


3

singleton方法是仅针对单个对象定义的方法。

例:

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的Singleton方法

测试


Singleton的test_obj方法

测试_2

test_3


1

实际上,如果您为Ruby项目编写任何C扩展,则实际上只有一种定义Module方法的方法。

rb_define_singleton_method

我知道这种自我交易只会带来其他各种问题,因此您可以通过搜索每个部分来做得更好。

首先对象。

foo = Object.new

我可以为foo创建方法吗?

当然

def foo.hello
 'hello'
end

我该怎么办?

foo.hello
 ==>"hello"

只是另一个对象。

foo.methods

您将获得所有Object方法以及新方法。

def foo.self
 self
end

foo.self

只是foo对象。

尝试看看如果从其他对象(如类和模块)中创建foo会发生什么。所有答案中的示例都很有趣,但是您必须使用不同的想法或概念才能真正理解代码编写方式所发生的事情。因此,现在您有很多术语需要研究。

出现了Singleton,Class,Module,self,Object和Eigenclass,但是Ruby并没有这样命名对象模型。它更像元类。理查德(Richard)或__为什么在这里展示您的想法。 http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html 如果让您大吃一惊,请尝试在搜索中查找Ruby Object Model。我在YouTube上知道的两个视频是Dave Thomas和Peter Cooper。他们也试图解释这个概念。戴夫花了很长时间才得到它,所以不用担心。我也还在努力。我为什么还要在这里?感谢您的提问。还要看一下标准库。与FYI一样,它具有一个Singleton模块。

很好 https://www.youtube.com/watch?v=i4uiyWA8eFk

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.