类方法是否有 alias_method ?

aar*_*ona 15 ruby alias-method

考虑以下类:

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

这没有问题,您可以毫无问题地拨打电话Foo.new.a_new_inst_method

我希望能够拥有一个类方法Foo.add_widget(*items)和别名,以便我可以执行以下操作:

Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'
Run Code Online (Sandbox Code Playgroud)

所以本质上它有一个“红宝石风格” 1.minute2.minutes所以我想别名一个Foo.add_widgetso 调用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
Run Code Online (Sandbox Code Playgroud)

但是,我收到以下错误:

NameError (undefined method `a_class_method' for class `Foo')
Run Code Online (Sandbox Code Playgroud)

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

3li*_*t0r 12

alias_method给接收者的实例方法取别名。类方法实际上是在单例类上定义的实例方法。

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

要别名定义在单例类上的实例方法,您可以使用class << object语法打开它。

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"
Run Code Online (Sandbox Code Playgroud)

或者您可以直接使用该singleton_class方法引用它。

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"
Run Code Online (Sandbox Code Playgroud)

如果你还在类上下文self中将引用该类。所以上面的也可以写成:

class MyClass
  class << self
    def a
      "Hello World!"
    end
    alias_method :b, :a
  end
end
Run Code Online (Sandbox Code Playgroud)

或者

class MyClass
  def self.a
    "Hello World!"
  end
  singleton_class.alias_method :c, :a
end
Run Code Online (Sandbox Code Playgroud)

或者两者的结合。


Ste*_*fan 5

您可以将类方法及其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
Run Code Online (Sandbox Code Playgroud)


Jör*_*tag 5

需要理解的重要一点是,Ruby 中没有类方法这样的东西

类方法实际上只是一个单例方法。类方法没有什么特别之处。每个对象都可以有单例方法。当对象是 a 时,我们只是将它们称为“类方法”,Class因为“”的实例的单例方法Class太长且笨拙。

等待!我说的是“单例方法”吗?

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

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

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

问题不是“这是一个类方法,还是一个单例方法”,而是“这个方法是在哪个模块中定义的?”

“单例方法”实际上是单例类中定义的实例方法。访问单例类的语法foo

class << foo
end
Run Code Online (Sandbox Code Playgroud)

还有一个方法Object#singleton_class可以返回对象的单例类。

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

一旦你理解了每个方法都是一个实例方法,而我们所说的“单例方法”只是单例类的实例方法,解决方案就很清楚了:

singleton_class.alias_method :a_new_class_method, :a_class_method
Run Code Online (Sandbox Code Playgroud)

注意:当我在上面写到“没有 X 这样的东西”时,我的意思是“在 Ruby 语言中没有 X 这样的东西”。但这并不意味着这些概念不存在在Ruby社区

我们经常讲“特殊方法”和“类方法”,只是因为它比谈论“singleton类的实例方法”或“单例类的对象恰好是实例的实例方法更简单Class类”。还有像连方法Object#define_singleton_methodObject#singleton_methodObject#singleton_methodsModule#private_class_methodModule#public_class_method,和Module#module_function在Ruby核心库。但是记住这些不是语言概念总是很重要的。这些是只存在于我们脑海中和一些库方法名称中的社区概念。