这是我的代码:
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 # => "@@@@@@@@@@@@@@@@@@@@"
任何人都可以解释我是如何得到这个结果的吗?我不明白这里的方法查找流程。
答案 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 # "$$$$$$$$$$$$$$$$$$$$"