首先,您需要了解 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 # "$$$$$$$$$$$$$$$$$$$$"