3

这是我的代码:

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         # => "@@@@@@@@@@@@@@@@@@@@"

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

4

3 回答 3

7

这就是我的看法:

Dollar::line

这个模块中没有定义这样的方法,所以它调用At::line是因为你包含了这个模块。

Star::line

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

Dollar::line

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

line

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

于 2015-07-09T14:05:55.197 回答
1

module Dollar
   def Star.line

故意的还是错字?

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

于 2015-07-09T14:15:52.413 回答
1

首先,您需要了解 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 # "$$$$$$$$$$$$$$$$$$$$"
于 2015-07-09T17:34:49.900 回答