【问题标题】:Should I use alias or alias_method?我应该使用别名还是 alias_method?
【发布时间】:2026-01-22 15:35:01
【问题描述】:

我在aliasalias_method 上找到了一篇博文。如该博客文章中给出的示例所示,我只想将一个方法别名为同一类中的另一个方法。我应该使用哪个?我总是看到alias 被使用,但有人告诉我alias_method 更好。

别名的使用

class User

  def full_name
    puts "Johnnie Walker"
  end

  alias name full_name
end

User.new.name #=>Johnnie Walker

别名方法的使用

class User

  def full_name
    puts "Johnnie Walker"
  end

  alias_method :name, :full_name
end

User.new.name #=>Johnnie Walker

Blog post link here

【问题讨论】:

  • 那篇文章没有回答你的问题吗?
  • @marcog:我已经读过了,但我不相信。在方法中定义别名,这不是我们应该经常做的事情。
  • @digitalextremist 链接有效
  • ruby 风格指南现在推荐alias“在词法类范围内为方法别名时”和alias_method“在运行时为模块、类或单例类的方法别名时”github.com/bbatsov/ruby-style-guide#alias-method-lexically跨度>

标签: ruby alias


【解决方案1】:

alias_method 可以根据需要重新定义。 (它在Module 类中定义。)

alias 的行为会根据其范围而变化,并且有时会非常不可预测。

结论:使用alias_method - 它为您提供了更多的灵活性。

用法:

def foo
  "foo"
end

alias_method :baz, :foo

【讨论】:

  • 不可预测是什么意思。天真地,有人会说不太灵活的选择将更可预测。另外,您能否提供任何从重新定义 alias_method 中受益的实际示例?
  • 示例用例:alias :new_method_name :old_method_namealias_method :new_method_name, :old_method_name
  • 他在这里寻找的词是更多预期的结果。 alias_method 是在运行时确定的,而不是在读取代码时确定的,例如 alias,因此它的行为更像是我们期望它的行为。
  • 期望方法在运行时动态定义并不是大多数程序员所期望的。至少这对我来说就像飞猪一样。
  • 对于defdefine_method 的争论可能相同:“如果需要,可以重新定义define_method。(它在Module 类中定义。)def 的行为会根据其范围而变化,有时可能会非常不可预测。结论:使用define_method - 它为您提供了更多的灵活性。”
【解决方案2】:

除了语法,主要区别在于作用域

# scoping with alias_method
class User

  def full_name
    puts "Johnnie Walker"
  end

  def self.add_rename
    alias_method :name, :full_name
  end

end

class Developer < User
  def full_name
    puts "Geeky geek"
  end
  add_rename
end

Developer.new.name #=> 'Geeky geek'

在上面的例子中,方法“name”选择了在“Developer”类中定义的方法“full_name”。现在让我们试试alias

class User

  def full_name
    puts "Johnnie Walker"
  end

  def self.add_rename
    alias name full_name
  end
end

class Developer < User
  def full_name
    puts "Geeky geek"
  end
  add_rename
end

Developer.new.name #=> 'Johnnie Walker'

使用别名的方法“name”不能选择在Developer中定义的方法“full_name”。

这是因为alias 是一个关键字,它是词法范围的。这意味着它将 self 视为读取源代码时 self 的值。相比之下,alias_methodself 视为在运行时确定的值。

来源:http://blog.bigbinary.com/2012/01/08/alias-vs-alias-method.html

【讨论】:

  • 由于这个答案给出了一个关于范围影响的实际例子,我比接受的答案更喜欢它。
【解决方案3】:

支持alias 而不是alias_method 的一点是它的语义被rdoc 识别,从而在生成的文档中产生整洁的交叉引用,而rdoc 完全忽略alias_method

【讨论】:

  • 也许 RDoc 应该开始将 alias_method 与别名一样对待。我们应该告诉他们;)
  • RDoc 应该如何理解在运行时评估的方法的后果?
  • @user1115652 你的意思是有人可能有猴子补丁alias_method吗?这似乎真的不太可能,如果有人这样做,那么他们应该愿意承担 RDoc 中的后果。如果您的观点是这是不可能的,那么您为什么这么认为?您认为 Yardoc 是如何做到的?
【解决方案4】:

我认为有一条不成文的规则(类似于约定)说使用“别名”仅用于注册方法名称别名,这意味着如果您想为代码的用户提供一个具有多个名称的方法:

class Engine
  def start
    #code goes here
  end
  alias run start
end

如果您需要扩展代码,请使用 ruby​​ 元替代方案。

class Engine
  def start
    puts "start me"
  end
end

Engine.new.start() # => start me

Engine.class_eval do
  unless method_defined?(:run)
    alias_method :run, :start
    define_method(:start) do
      puts "'before' extension"
      run()
      puts "'after' extension"
    end
  end
end

Engine.new.start
# => 'before' extension
# => start me
# => 'after' extension

Engine.new.run # => start me

【讨论】:

    【解决方案5】:

    在提出这个问题一年后,出现了一篇关于该主题的新文章:

    http://erniemiller.org/2014/10/23/in-defense-of-alias/

    似乎“这么多男人,这么多头脑”。前一篇文章作者鼓励使用alias_method,而后者建议使用alias

    但是,在上面的博文和答案中,这些方法都有一个共同的概述:

    • 如果要将别名限制在定义的范围内,请使用 alias
    • 使用alias_method 允许继承的类访问它

    【讨论】:

      【解决方案6】:

      rubocop gem 贡献者在他们的Ruby Style Guide 中提出建议:

      在词法类范围内为方法起别名时首选别名作为 在这种情况下,自我的解决也是词法的,它 向用户清楚地传达您的别名的间接性 不会在运行时或由任何子类更改,除非做出 明确的。

      class Westerner
        def first_name
         @names.first
        end
      
       alias given_name first_name
      end
      

      在为模块、类或 运行时的单例类,因为别名的词法范围导致 这些情况下的不可预测性

      module Mononymous
        def self.included(other)
          other.class_eval { alias_method :full_name, :given_name }
        end
      end
      
      class Sting < Westerner
        include Mononymous
      end
      

      【讨论】:

        【解决方案7】:

        alias_method new_methodold_method

        old_method 将在一个类或模块中声明,该类或模块现在被继承到我们将使用 new_method 的类。

        这些可以是变量或方法。

        假设 Class_1 有 old_method,Class_2 和 Class_3 都继承 Class_1。

        如果 Class_2 和 Class_3 的初始化在 Class_1 中完成,那么两者在 Class_2 和 Class_3 中可以有不同的名称及其用法。

        【讨论】: