该类的本征类(或元类)中的类方法和方法只有两种方法来定义一个东西吗?
否则,有什么区别?
class X
# class method
def self.a
"a"
end
# eigenclass method
class << self
def b
"b"
end
end
end
X.a
和X.b
的行为方式有何不同?
我认识到我可以通过打开特征类来覆盖或别名类方法:
irb(main):031:0> class X; def self.a; "a"; end; end
=> nil
irb(main):032:0> class X; class << self; alias_method :b, :a; end; end
=> #<Class:X>
irb(main):033:0> X.a
=> "a"
irb(main):034:0> X.b
=> "a"
irb(main):035:0> class X; class << self; def a; "c"; end; end; end
=> nil
irb(main):036:0> X.a
=> "c"
答案 0 :(得分:11)
这两种方法是等价的。 'eigenclass'版本有助于使用attr_ *方法,例如:
class Foo
@instances = []
class << self;
attr_reader :instances
end
def initialize
self.class.instances << self
end
end
2.times{ Foo.new }
p Foo.instances
#=> [#<Foo:0x2a3f020>, #<Foo:0x2a1a5c0>]
您还可以使用define_singleton_method
在课程上创建方法:
Foo.define_singleton_method :bim do "bam!" end
答案 1 :(得分:6)
在Ruby中,确实没有类方法这样的东西。由于一切都是Ruby中的对象(包括类),当你说def self.class_method
时,你只是在类Class
的实例上定义一个单例方法。所以回答你的问题,说
class X
def self.a
puts "Hi"
end
class << self
def b
puts "there"
end
end
end
X.a # => Hi
X.b # => there
是说同一件事的两种方式。这两种方法都只是在您的Class对象实例中定义的singeton(eigen,meta,ghost或任何你想称之为的方法)方法,在你的例子中是X
。这个主题是元编程的一部分,这是一个有趣的话题,如果你已经使用Ruby一段时间了,你应该看看。
实用程序员有一个很棒的book元编程,如果你对这个主题感兴趣,你一定要看看。
答案 2 :(得分:3)
另一位死灵法师在这里发现了这个老问题......你可能没有意识到的一件事是将类方法标记为private
(使用私有关键字而不是:private_class_method
)是不同的而不是标记本征类方法。 :
class Foo
class << self
def baz
puts "Eigenclass public method."
end
private
def qux
puts "Private method on eigenclass."
end
end
private
def self.bar
puts "Private class method."
end
end
Foo.bar
#=> Private class method.
Foo.baz
#=> Eigenclass public method.
Foo.qux
#=> NoMethodError: private method `qux' called for Foo:Class
# from (irb)
以下示例将与前一个示例有关:
class Foo
class << self
def baz
puts "Eigen class public method."
end
private
def qux
puts "Private method on eigenclass."
end
end
def bar
puts "Private class method."
end
private_class_method :bar
end
Foo.bar
#=> NoMethodError: private method `bar' called for Foo:Class
# from (irb)
Foo.baz
#=> Eigen class public method.
Foo.qux
#=> NoMethodError: private method `qux' called for Foo:Class
# from (irb)
答案 3 :(得分:1)
Ruby中使用的大多数实例方法都是全局方法。这意味着它们可以在定义它们的类的所有实例中使用。相反,单个方法是在单个对象上实现的。
有一个明显的矛盾。 Ruby在类中存储方法,所有方法都必须与类相关联。定义单例方法的对象不是类(它是类的实例)。如果只有类可以存储方法,那么对象如何存储单例方法?创建单例方法时,Ruby会自动创建一个匿名类来存储该方法。这些匿名类称为元类,也称为单例类或特征类。单例方法与元类相关联,而元类又与定义单例方法的对象相关联。
如果在单个对象中定义了多个单例方法,则它们都存储在同一个元类中。
class Zen
end
z1 = Zen.new
z2 = Zen.new
def z1.say_hello # Notice that the method name is prefixed with the object name
puts "Hello!"
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
在上面的例子中,say_hello方法是在Zen类的z1实例中定义的,而不是在z2实例中定义的。
以下示例显示了定义单例方法的不同方法,结果相同。
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'…
在上面的例子中,类&lt;&lt; z1将当前self改为指向z1对象的元类;然后,它定义了元类中的say_hello方法。
以上两个例子都用于说明单例方法的工作原理。但是,有一种更简单的方法来定义单例方法:使用名为define_singleton_method的内置方法。
class Zen
end
z1 = Zen.new
z2 = Zen.new
z1.define_singleton_method(:say_hello) { puts "Hello!" }
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
我们之前了解到类也是对象(内置类的实例,称为Class)。我们还学习了类方法。 类方法只不过是与类对象关联的单例方法。
又一个例子:
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
所有对象都可能有元类。这意味着类也可以有元类。在上面的例子中,类&lt;&lt; self修饰self,因此它指向Zabuton类的元类。如果定义的方法没有显式接收器(将在其上定义方法的类/对象),则在当前作用域内隐式定义它,即self的当前值。因此,stuff方法是在Zabuton类的元类中定义的。上面的例子只是另一种定义类方法的方法。