考虑以下类:
class Foo
def an_inst_method
'instance method'
end
def self.a_class_method
'class method'
end
alias_method :a_new_inst_method, :an_inst_method
end
这没有问题,您可以毫无问题地调用Foo.new.a_new_inst_method
。
我希望有一个像Foo.add_widget(*items)
这样的类方法并将其别名,这样我就可以做一些事情,比如:
Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'
所以本质上它有一个"ruby风格",比如1.minute
和2.minutes
,所以我想给Foo.add_widget
取一个别名,所以调用Foo.add_widgets
调用完全相同的方法。我知道我可以把它包起来,但我觉得我应该能用更干净的方式来做。
想想我尝试这样的东西:
class Foo
def an_inst_method
'instance method'
end
def self.a_class_method
'class method'
end
alias_method :a_new_inst_method, :an_inst_method
alias_method :a_new_class_method, :a_class_method
end
然而,我得到以下错误:
NameError (undefined method `a_class_method' for class `Foo')
所以看起来这对类方法不起作用。我该怎么做?
alias_method
对接收器的实例方法进行别名。类方法实际上是在类的singleton类上定义的实例方法。
class MyClass
def self.a
"Hello World!"
end
end
method_1 = MyClass.method(:a).unbind
method_2 = MyClass.singleton_class.instance_method(:a)
method_1 == method_2
#=> true
要对在singleton类上定义的实例方法进行别名,可以使用class << object
语法打开它。
class << MyClass
alias_method :b, :a
end
MyClass.b
#=> "Hello World!"
也可以使用singleton_class
方法直接引用。
MyClass.singleton_class.alias_method :c, :a
MyClass.c
#=> "Hello World!"
如果您仍在类上下文中,self
将引用该类。所以上面也可以写成:
class MyClass
class << self
def a
"Hello World!"
end
alias_method :b, :a
end
end
或
class MyClass
def self.a
"Hello World!"
end
singleton_class.alias_method :c, :a
end
或者两者的结合。
需要理解的重要一点是,在Ruby中没有类方法。
类方法实际上只是一个单例方法。类方法没有什么特别之处每个对象都可以有singleton方法。当对象是Class
时,我们只将它们称为"类方法",因为"Class
实例的singleton方法"太长且难以处理。
等等!我说的是"singleton方法"吗?
另一件需要理解的重要事情是,在Ruby中没有singleton方法这样的东西。
singleton方法实际上只是singleton类的一个常规的无聊的旧实例方法。singleton方法没有什么特别之处。它们和其他实例方法一样,只是实例方法。
事实上,Ruby只有实例方法。没有函数,没有构造函数,没有静态方法,没有类方法,没有模块函数,没有单例方法。
问题不是"这是一个类方法吗,这是一种单例方法吗",而是"中定义了该方法的哪个模块?">
"Singleton方法"实际上是在Singleton类中定义的实例方法。访问foo
的singleton类的语法是
class << foo
end
还有一个方法Object#singleton_class
,它返回对象的singleton类。
为什么我如此积极地抨击每个方法都是实例方法而类方法不存在的事实?因为这意味着Ruby的对象模型比人们想象的要简单得多!毕竟,在您的问题中,您已经表明您知道如何对实例方法进行别名,但您说您不知道如何对类方法进行别名。但是,这是错误的!您确实知道如何别名类方法,因为它们只是实例方法。如果你被正确地教导了这个事实,你就永远不需要问这个问题!
一旦您了解了每个方法都是一个实例方法,并且我们所称的"singleton方法"只是singleton类的实例方法,那么解决方案就变得清晰起来:
singleton_class.alias_method :a_new_class_method, :a_class_method
注意:当我在上面写"没有X这样的东西"时,我的意思是"在Ruby语言中没有X这样的东西"。不是并不意味着这些概念在Ruby社区中不存在。
我们经常讨论"singleton方法"one_answers"类方法",因为这比谈论"singleton类的实例方法"或"恰好是Class
类实例的对象的singleton类实例方法"更容易。Ruby核心库中甚至有Object#define_singleton_method
、Object#singleton_method
、Object#singleton_methods
、Module#private_class_method
、Module#public_class_method
和Module#module_function
等方法。但重要的是要记住,这些是而不是语言概念。这些社区概念只存在于我们的头脑中和一些库方法的名称中。
您可以将类方法及其alias_method
调用封装到一个单独的模块中,并通过extend
:将该模块合并到您的类中
class Foo
def an_inst_method
'instance method'
end
alias_method :a_new_inst_method, :an_inst_method
module ClassMethods
def a_class_method
'class method'
end
alias_method :a_new_class_method, :a_class_method
end
extend ClassMethods
end
好吧,看起来我可以做这样的事情,它会起作用:
class Foo
def an_inst_method
'instance method'
end
def self.a_class_method
'class method'
end
alias_method :a_new_inst_method, :an_inst_method
class << self
alias_method :a_new_class_method, :a_class_method
end
end
Foo.a_class_method # => "class method"
Foo.a_new_class_method # => "class method"
如果有人在这里有任何关于Ruby语言的有用信息,并且想提交一个全面的答案,我会给你+1。
alias_method
对实例进行操作,因此需要更深入地对Class
实例或类的元类进行操作。Ruby有一个狂野的物体模型,它可能会让人心碎,但它也会给你很大的力量:
class Foo
def an_inst_method
'instance method'
end
alias_method :a_new_inst_method, :an_inst_method
class << self
def a_class_method
'class method'
end
alias_method :a_new_class_method, :a_class_method
end
end