Ruby中的模块方法

时间:2015-07-09 13:47:21

标签: ruby inheritance module singleton-methods

这是我的代码:

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

任何人都可以解释我是如何得到这个结果的吗?我不明白这里的方法查找流程。

3 个答案:

答案 0 :(得分:7)

这就是我的看法:

Dollar::line

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

Star::line

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

Dollar::line

第三次通话与第一次通话相同。

line

最后一个是At::line,因为你制作了一个包含。

答案 1 :(得分:1)

module Dollar
   def Star.line

故意还是错字?

似乎未定义Dollar.line,而是使用line中的方法At

答案 2 :(得分: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 # "$$$$$$$$$$$$$$$$$$$$"