【问题标题】:Is there an alias_method for a class method? [duplicate]类方法是否有 alias_method? [复制]
【发布时间】:2020-08-03 10:13:16
【问题描述】:

考虑以下类:

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'

所以本质上它具有像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')

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

【问题讨论】:

  • 问题很相似,但它是在 Rails 上下文中。解决方案会回答我的问题,但我几乎可以肯定他可能会利用 Arel 来解决他的问题。我发布的问题纯粹是作为一个 Ruby 问题设计的,因此更容易搜索。您可能想建议编辑他的问题的标题,因为当我搜索我的问题的解决方案时它没有出现。
  • 是的,不幸的是,另一个问题具有误导性且完全不相关的 Rails 上下文,对于某些人来说可能更难找到。恕我直言,它仍然是一个完美的 content 副本,虽然不是 topic 副本。答案也是一样的。无论如何,仍然是你的一个好问题。 旁注:当我在审核期间将您标记为受骗者时,审核系统打了我耳光并严重指责我没有注意,这本身就是一个荒谬的主张,因为找到(潜在的)受骗者需要相当多的注意力。简直不敢相信这以前没有出现过。
  • 之前没有针对我的特定问题或您所做的其他评论提出过问题?你收到什么讯息?我很好奇。
  • 当我在审核期间阅读您的问题时,我指的是我,当我立即想到“我确定这已经得到了回答”。

标签: ruby alias-method


【解决方案1】:

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

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。

【讨论】:

  • 当您执行class &lt;&lt; self 后跟alias_method :a_new_class_method, :a_class_method 时,您实际上是在Foo 的单例类上调用alias_method。另一种写法是:singleton_class.alias_method :a_new_class_method, :a_class_method 在类上下文中。
  • 您还想从答案中得到什么?我的意思是,这可能是最干净的解决方案。
  • @DaveNewton 你是对的,但因为我也有一个理念,如果有人可以为问题提供任何更有意义的信息,即使它间接解决了问题,我认为这也应该得到回报。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    alias_method 为接收者的实例方法取别名。类方法实际上是定义在类的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 &lt;&lt; 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
    

    或者两者的结合。

    【讨论】:

      【解决方案4】:

      您可以将类方法及其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
      

      【讨论】:

        【解决方案5】:

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

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

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

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

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

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

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

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

        class << foo
        end
        

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

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

        一旦你明白每个方法都是一个实例方法,而我们所说的“单例方法”只是单例类的实例方法,那么解决方案就变得清晰了:

        singleton_class.alias_method :a_new_class_method, :a_class_method
        

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

        我们经常谈论“单例方法”和“类方法”,只是因为它比谈论“单例类的实例方法”或“恰好是一个实例的对象的单例类的实例方法”容易Class 类”。 Ruby 核心库中甚至还有Object#define_singleton_methodObject#singleton_methodObject#singleton_methodsModule#private_class_methodModule#public_class_methodModule#module_function 等方法。但始终重要的是要记住,这些是不是语言概念。这些是社区概念,只存在于我们的头脑中和一些库方法的名称中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-16
          • 2013-01-03
          • 2017-08-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多