Dav*_*mar 3 ruby class eigenclass
我无法理解红宝石中特征类或单例类的概念。我读了很多,认为 eigenclass是一个类的类。这对我来说没有意义,因为对我来说,类的类实际上是Class因为所有类实际上都是类的实例Class。
另一件我不太明白的事情是下面的说法:类方法实际上是类 eigenclass 的实例方法。特征类可以通过以下方式访问:
YourClass = Class.new
class << YourClass
def class_method
end
end
Run Code Online (Sandbox Code Playgroud)
但是,如果特征类确实是 YourClass 类(即Class),那么前面的代码不应该打开该类Class并向其添加实例方法class_method,使其可供所有未来的实例访问(即在未来)?
我实际上感觉单例类与Class. 当你这样做时:
class MyClass
end
MyClass.singleton_class
Run Code Online (Sandbox Code Playgroud)
你得到的#<Class:MyClass>结果与输出不同MyClass.class => Class
#<Class:MyClass>那个输出是什么?这与命名空间无关,否则会有两个:Class::MyClass...
我正在寻找对本征类概念的简单且明确的解释,以澄清我的想法。
Ste*_*fan 11
单例类包含特定于单个对象的方法。
\n\n对于通用对象来说,这是一个很好的功能。但对于课堂来说,这是至关重要的。让我们从对象开始:
\n\n实例方法通常在类中定义。同一类的所有实例共享相同的实例方法。单例类位于对象及其类之间。它允许每个实例拥有自己的一组方法,独立于其他实例。
\n\n如果我们有两个类,Foo并且Bar每个类都有 2 个实例a,b和c, d:
class Foo ; end\nclass Bar ; end\n\na = Foo.new #=> #<Foo:0x00007fc280963008>\nb = Foo.new #=> #<Foo:0x00007f8319016b18>\nc = Bar.new #=> #<Bar:0x00007fa66c8d7290>\nd = Bar.new #=> #<Bar:0x00007f94d5106ac8>\nRun Code Online (Sandbox Code Playgroud)\n\n您将拥有这样的类结构:(简化,不包括模块)
\n\nclass Foo ; end\nclass Bar ; end\n\na = Foo.new #=> #<Foo:0x00007fc280963008>\nb = Foo.new #=> #<Foo:0x00007f8319016b18>\nc = Bar.new #=> #<Bar:0x00007fa66c8d7290>\nd = Bar.new #=> #<Bar:0x00007f94d5106ac8>\nRun Code Online (Sandbox Code Playgroud)\n\nRuby 会惰性地创建这些单例类,例如在调用singleton_class.
所以定义方法时a.hello,它不是存储在a类中Foo,而是存储在a单例类中:
def a.hello\n \'hello from a\'\nend\n\na.method(:hello).owner\n#=> #<Class:#<Foo:0x00007fc280963008>> <-- a\'s singleton class\nRun Code Online (Sandbox Code Playgroud)\n\n因此,即使两者都是实例b,也看不到该方法:Foo
b.hello #=> NoMethodError: undefined method `hello\'\nRun Code Online (Sandbox Code Playgroud)\n\n我们甚至可以定义一个同名的方法,而不b干扰a:
def b.hello\n \'hello from b\'\nend\n\nb.method(:hello).owner\n#=> #<Class:#<Foo:0x00007f8319016b18>> <-- b\'s singleton class\n\na.hello #=> "hello from a"\nb.hello #=> "hello from b"\nRun Code Online (Sandbox Code Playgroud)\n\n我们还可以定义一个泛型hello并Foo在每个实例级别覆盖它:(您通常不会这样做,但这是可能的)
class Foo\n def hello\n \'hello\'\n end\nend\n\ndef a.hello\n "#{super} from a"\nend\n\ndef b.hello\n "b says #{super.upcase}!"\nend\n\na.hello #=> "hello from a"\nb.hello #=> "b says HELLO!"\n\nc = Foo.new\nc.hello #=> "hello"\nRun Code Online (Sandbox Code Playgroud)\n\n上述内容对于课堂尤其重要。每个类都是一个实例Class:
Foo.class #=> Class\nRun Code Online (Sandbox Code Playgroud)\n\n假设我们想要一个方法Foo.hello,我们在哪里定义它?
实例方法通常定义在实例的类中,因此我们可以Foo在类中定义它:
class Class\n def hello\n \'Hello from Foo\'\n end\nend\n\nFoo.hello\n#=> "Hello from Foo"\nRun Code Online (Sandbox Code Playgroud)\n\n但这将使该方法可用于 的所有实例Class:
Bar.hello\n#=> "Hello from Foo"\n\nString.hello\n#=> "Hello from Foo"\nRun Code Online (Sandbox Code Playgroud)\n\n最好有一个实例专用的地方Foo。那个地方是Foo\ 的单例类:
def Foo.hello\n \'Hello from Foo\'\nend\nRun Code Online (Sandbox Code Playgroud)\n\n或者
\n\nclass Foo\n def self.hello # <-- self is Foo, so this is just "def Foo.hello"\n \'hello from Foo\'\n end\nend\nRun Code Online (Sandbox Code Playgroud)\n\n就像a.hello上面一样,此方法仅适用于Foo:
Foo.hello #=> "hello from Foo"\nBar.hello #=> NoMethodError\nRun Code Online (Sandbox Code Playgroud)\n\n我们将这些方法称为类方法,但它们实际上只是单例类的实例方法:
\n\nFoo.method(:hello).owner\n#=> #<Class:Foo> <-- Foo\'s singleton class\n\nFoo.method(:hello).unbind == Foo.singleton_class.instance_method(:hello)\n#=> true\nRun Code Online (Sandbox Code Playgroud)\n\n如果您将类的单例方法与对象的单例方法进行比较,您会发现它们是相同的。这是因为在 Ruby 中,类也是对象,并且所有对象的工作方式都是相似的。
\n