这个Ruby(2.2.3p173)代码:
class A
def msg
"hello"
end
def p
Proc.new { msg }
end
def lam
lambda { msg }
end
def blk
(1..3).map { msg }.join(" and ")
end
def d1(obj)
obj.define_singleton_method(:say1) { msg }
end
def d2(obj)
bound = msg # <== Why is this needed?
obj.define_singleton_method(:say2) { bound }
end
end
a = A.new
puts a.p.call
puts a.lam.call
puts a.blk
obj = Object.new
a.d1(obj)
begin
# Why does this fail?
puts obj.say1
rescue
puts "caught: #{$!}"
end
a.d2(obj)
puts obj.say2
生成此输出:
hello
hello
hello and hello and hello
caught: undefined local variable or method `msg' for #<Object:0x00000001a20638>
hello
d1和d2有什么区别?为什么所有的块都看到了msg,除了传递给define_singleton_method的那个?
更新
我认为归结为:
Proc主体有一个像Lisp和。中的函数一样的词法范围 JavaScript,意思是当Ruby遇到一个自由变量时 proc体,它的值在proc的上下文中被解析 定义。这就是使封闭成为可能的原因。方法不同, 然而。方法的上下文是它们绑定的对象。 当Ruby遇到方法体内的自由变量时,它会假定 变量引用对象的另一个方法,这就是什么 使我们不必使用&#34;这个&#34;前缀同一对象方法。要么 &#34;自&#34;
我在这里找到:Of closures, methods, procs, scope, and Ruby。
{ msg }
所有这些不同的块必须像Proc主体那样工作。 define_singleton_method
正在采取措施并为其提供方法规则。
答案 0 :(得分:1)
答案与self
和范围
在ruby中创建新范围有三种方法。 类,模块和方法。
您的类创建了一个范围,您的每个方法都创建一个包含特定于它们的绑定的范围。闭包很特别。当您定义块时,闭包将捕获周围的绑定,并且块结束后块特定绑定将消失。例如:
def my_method
#Method scope
x = "Goodbye"
yield("Cruel")
end
x = "Hello"
#Closure says "I am going to grab the local bindings from my scope
my_method {|y| "#{x}, #{y} world" }
什么时候编写代码
obj.define_singleton_method(:say1) { msg }
闭包抓取的唯一本地绑定是&#39; obj&#39; 这可以通过修改代码来证明:
def d2(obj)
puts "in the scope of method :d2, I have acces to the :msg method: #{methods.include?(:msg)}"
puts "---"
obj.define_singleton_method(:say2) do
puts "in the scope of this closure, I have acces to the :msg method: #{methods.include?(:msg)}"
puts "Things I do have access to: "
puts methods
puts local_variables
end
end
ruby self最重要部分的简单打印声明将向您显示您在不同的范围内操作。看看下面的代码:
def d2(obj)
puts "in the scope of method :d2, I am operating as #{self}"
puts "---"
obj.define_singleton_method(:say2) do
puts "in the scope of this closure, I am operating as #{self}"
end
end
简而言之,原因在于范围。每当您声明bound = msg
时,您正在使msg
的内容为方法本地,然后闭包然后可以获取msg
的本地绑定值。
如果你想了解更多关于它是如何工作的,我强烈推荐&#34;实用程序员 - 元编程Ruby&#34;你将学到很多关于自我和闭包的知识。 http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Facets/dp/1941222129
---- ---- EDIT &#34;为什么&#34;
def p
Proc.new { msg }
end
与
不同 def d2(obj)
obj.define_singleton_method(:say2) { msg }
end
这是不同的,因为块内的自我是不同的。在方法定义&#34; p&#34;中,块可以访问实例变量和方法,而方法&#34; d2&#34;有一个只能访问Object的块。我们可以通过一点点monkeypatching来证明这一点。添加以下代码:
class Object
def msg
"GoodBye"
end