在添加Kernel
使它们在全球范围内可用的方法时,我发现有些奇怪。这很有趣,我正在寻找一些文档或很好的解释。
让我们看一下代码:
文件:./ demo.rb
# example 1
module Kernel
def foo
puts "I'm defined inside the module!"
end
end
# example 2
module Bar
def bar
puts "I'm included! (bar)"
end
end
Kernel.send :include, Bar
# example 3
module Baz
def baz
puts "I'm included! (baz)"
end
end
module Kernel
include Baz
end
然后,在bash和IRB中
$ irb -r ./demo.rb
> foo
# I'm defined inside the module!
> bar
# NameError: undefined local variable or method `bar' for main:Object
> baz
# NameError: undefined local variable or method `baz' for main:Object
>
> self.class.ancestors
# => [Object, Kernel, BasicObject]
>
> include Kernel
>
> self.class.ancestors
# => [Object, Kernel, Baz, Bar, BasicObject]
>
> foo
# I'm defined inside the module!
> bar
# I'm included! (bar)
> baz
# I'm included! (baz)
foo
可以正常工作,并且可用于包含的所有对象Kernel
。bar
并且baz
,在另一方面,不能立即使用。
我想这是因为IRB(an )的评估上下文Object
已经包含Kernel
,并且在模块B内包含模块A不会“重新加载” B的所有先前包含的内容。
好的,这是很合理的,事实上,重新包含Kernel
将添加其他两种方法。
然后,我的问题是:
Kernel
工作?(示例1)您foo.bar
在Ruby中调用会发生什么?像这样:
foo.class.ancestors.each do |klass|
if klass.public_instance_methods.include? :bar
return klass.instance_method(:bar).bind(foo).call
end
end
raise NameError
即Ruby在祖先中搜索以找到匹配的实例方法。
当您调用A.include B
Ruby时会发生什么?像这样:
B.ancestors.each do |mod|
A.ancestors << mod unless A.ancestors.include? mod
end
B
并且它的所有祖先都成为了祖先A
。这两种行为可以解释一切:
Kernel
有效的,因为它包含在Object
每个对象中,因此它是每个对象的祖先,这意味着只要您在任何对象上调用方法,都可以搜索它的方法(包括新方法)。Kernel
仅在包含时才搜索祖先,这是在您添加新祖先之前。本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句