在Ruby中的类<< self idiom

ran*_*its 836 ruby singleton metaclass eigenclass

是什么class << self在Ruby中做什么?

Chr*_*ung 879

首先,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"
Run Code Online (Sandbox Code Playgroud)

现在,回答这个问题:class << self打开self单例类,以便可以为当前self对象重新定义方法(在类或模块体内部是类或模块本身).通常,这用于定义类/模块("静态")方法:

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"
Run Code Online (Sandbox Code Playgroud)

这也可以写成速记:

class String
  def self.value_of obj
    obj.to_s
  end
end
Run Code Online (Sandbox Code Playgroud)

甚至更短:

def String.value_of obj
  obj.to_s
end
Run Code Online (Sandbox Code Playgroud)

在函数定义内部时,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
Run Code Online (Sandbox Code Playgroud)

因此,在上面的示例中,每个实例StateMachineExample都有process_hook别名process_state_1,但请注意在后者中,它可以重新定义process_hook(self仅用于,不影响其他StateMachineExample实例)process_state_2.因此,每次调用者调用该process方法(调用可重新定义的方法process_hook)时,行为都会根据其所处的状态而变化.

  • @Jörg:编辑+1(我希望SO能够进行编辑;哦,好吧).这确实是`class << self`更常见的用法,用于创建类/模块方法.我可能会扩展使用`class << self`,因为这是一种更惯用的用法. (20认同)
  • gsub!("eigenclass","singleton class"),请参阅即将发​​布的方法http://redmine.ruby-lang.org/repositories/revision/1?rev=27022 (4认同)
  • 引用`a`的`singleton_class`实在令人困惑,因为`a`的类(更改`inspect`之后)是`String`类的唯一变体.如果它正在改变单例`String`类,它将影响所有其他`String`实例.更奇怪的是,如果你以后重新打开`String`来重新定义`inspect`,那么'a`仍会接受新的变化. (4认同)
  • 我发现表达式"打开一个对象的单例类" - 我以前读过很多次 - 含糊不清.据我所知,Ruby文档中没有任何地方"开放"一个定义的类,即使我们都知道它的含义.`class << self`是否意味着什么比`self`的值设置为等于块范围内的单例类? (3认同)

Sam*_*adi 31

我发现了大约一个超级简单的解释class << self,Eigenclass以及不同类型的Eigenclass在这个博客.

在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
Run Code Online (Sandbox Code Playgroud)

访问class <<(包括单例方法)的另一种方法是使用以下语法(self):

foo = Foo.new

class << foo
  def a_singleton_method
    puts "I am a singleton method"
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,您可以在此上下文中定义一个单例方法,Foo该方法就是类class << self本身:

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
Run Code Online (Sandbox Code Playgroud)

  • 实际上Singleton方法和Class方法是相同的,它们都存在于singleton类中.你可以使用```foo.singleton_class.instance_methods(false)```来检查. (4认同)

Bru*_*cca 20

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

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'…
Run Code Online (Sandbox Code Playgroud)

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

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

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

所有对象都可能有元类.这意味着类也可以有元类.在上面的例子中,类<< self修改self,因此它指向Zabuton类的元类.如果定义的方法没有显式接收器(将在其上定义方法的类/对象),则在当前作用域内隐式定义它,即self的当前值.因此,stuff方法是在Zabuton类的元类中定义的.上面的示例只是定义类方法的另一种方法.恕我直言,最好使用def self.my_new_clas_method语法来定义类方法,因为它使代码更容易理解.上面的例子被包含在内,所以我们理解当我们遇到类<< self syntax时发生的事情.

有关Ruby Classes的更多信息可以在这篇文章中找到.

  • 在审查了这个问题的各种来源之后,您的回答确实完美地澄清了一切。谢谢你! (2认同)

lak*_*are 14

什么类<<东西做:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end
Run Code Online (Sandbox Code Playgroud)

[它 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
Run Code Online (Sandbox Code Playgroud)

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]


顺便说一下 - 他们调用object的singleton class == metaclass == eigenclass.