class 方法有 alias_method 吗?

Is there an alias_method for a class method?

考虑以下 class:

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) 这样的 class 方法并给它起别名,这样我就可以做类似的事情:

Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'

所以本质上它有一个 "ruby style" 就像 1.minute2.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')

所以看起来这不适用于 class 方法。我该怎么做?

好的,看起来我可以做这样的事情并且它会起作用:

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 实例,或 class' metaclass。 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

alias_method 别名接收方的实例方法。 Class 方法实际上是在 class.

singleton class 上定义的实例方法
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

要为单例 class 上定义的实例方法设置别名,您可以使用 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!"

如果您仍在 class 上下文中,self 将引用 class。所以上面也可以写成:

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

或两者结合。

您可以将 class 方法及其 alias_method 调用包装到一个单独的模块中,然后通过 extend:

将该模块合并到您的 class 中
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

需要理解的重要一点是 在 Ruby 中没有 class 方法 这样的东西。

一个class方法实际上只是一个单例方法。 class 方法没有什么特别之处。 每个对象 都可以有单例方法。当对象是 Class 时,我们只称它们为 "class methods",因为 "singleton method of an instance of Class" 太长且笨重。

等等!我有说 "singleton method" 吗?

另一个需要理解的重要事情是在Ruby中没有单例方法

单例方法实际上只是单例的常规无聊的旧实例方法class。单例方法没有什么特别之处。它们只是像任何其他实例方法一样的实例方法。

事实上,Ruby只有个实例方法。没有函数,没有构造函数,没有静态方法,没有 class 方法,没有模块函数,没有单例方法。

问题不是"is this a class method, is this a singleton method",而是"which module is this method defined in?"

"Singleton methods" 是真正定义在单例中的实例方法 class。访问 foo 的单例 class 的语法是

class << foo
end

还有一个方法Object#singleton_class,returns对象的单例class。

为什么我如此积极地强调 每个方法 都是实例方法而 class 方法不存在这一事实?因为这意味着Ruby的对象模型比人们想象的要简单得多!毕竟,在您的问题中,您已经表明您知道如何为实例方法设置别名,但您说您不知道如何为 class 方法设置别名。但是,那是错误的!您 知道如何为 class 方法设置别名,因为 它们只是实例方法。如果你被正确地教导了这个事实,你永远不需要问这个问题!

一旦你明白了每个方法都是一个实例方法,而我们所说的"singleton methods"只是单例的实例方法class,解决方案就很清楚了:

singleton_class.alias_method :a_new_class_method, :a_class_method

注意:上面写的"there is no such thing as X",我的意思是"there is no such thing as X in the Ruby language"。这确实 意味着 在 Ruby 社区.

中不存在这些概念

我们经常谈论 "singleton methods" 和 "class methods",只是因为它比谈论 "instance methods of the singleton class" 或 "instance methods of the singleton class of an object which happens to be an instance of the Class class" 更容易。 Ruby核心库中甚至还有Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, and Module#module_function这样的方法。但请务必记住,这些 不是 语言概念。这些是 社区 概念,只存在于我们的头脑中 和一些库方法的名称中。