Ruby 中的模块方法

Module methods in Ruby

这是我的代码:

module Star
  def Star.line
    puts '*' * 20
  end
end

module Dollar
  def Star.line
    puts '$' * 20
  end
end

module At
  def line
    puts '@' * 20
  end
end

include At
Dollar::line # => "@@@@@@@@@@@@@@@@@@@@"
Star::line   # => "$$$$$$$$$$$$$$$$$$$$"
Dollar::line # => "@@@@@@@@@@@@@@@@@@@@"
line         # => "@@@@@@@@@@@@@@@@@@@@"

谁能解释一下我是如何得到这个结果的?我不明白这里的方法查找流程。

我是这样看的:

Dollar::line

此模块中没有定义此类方法,因此调用 At::line 因为您包含了此模块。

Star::line

它使用来自 Dollar 模块的最后定义(它遵循原始 Star 定义,因此被覆盖)。

Dollar::line

第三次调用与第一次相同。

line

最后一个是 At::line 因为你做了一个包含。

module Dollar
   def Star.line

是故意的还是打字错误?

貌似Dollar.line没有定义,改用At中的方法line

首先您需要了解 Ruby 查找常量与查找方法有点相似。它首先在当前 词法范围 中查找常量。如果它在那里没有找到常量,它会上升一级并在那里寻找,依此类推。如果它在其他地方找不到常量,它最终会搜索顶层,这就是为什么您可以从代码中的任何位置访问 Kernel 等模块。

module Star
end
Star.object_id # 20

module Dollar
  Star.object_id # 20. No Star in current scope, so gets the top-level star
end

module At
  module Star
  end
  Star.object_id # 10. There is now a Star in this scope, so we don't get the top-level one
end

接下来要了解的是 Ruby 中顶层定义的方法是 Object实例 方法。由于 Ruby 中的所有内容都是 Object 的实例,因此始终可以调用此类方法。

最后,考虑一下 include 的作用:它从模块中获取实例方法,并使它们成为当前作用域中的实例方法。因此,如果您 include 位于顶层的内容,所有这些方法都会添加到 Object!

所以你的代码基本上等同于:

module Star
  def self.line
    puts '*' * 20
  end

  # this overwrites the previous definition
  def self.line
    puts '$' * 20
  end
end

# because of the way constants are looked up, the def ends up in Star
module Dollar
end

module At
  def line
    puts '@' * 20
  end
end

# the include does this, so now every object (including Dollar) can call line
def line
  puts '@' * 20
end

# except Star already has its own line method, so the one from Object won't be called for it
Star.line # "$$$$$$$$$$$$$$$$$$$$"