这个
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 bodies have a lexical scope like functions in Lisp and
JavaScript, meaning that when Ruby encounters a free variable inside a
proc body, its value is resolved within the context the proc was
defined. This is what makes closures possible. Methods are different,
however. A method’s context is the object to which they are bound.
When Ruby encounters a free variable inside a method body, it assumes
the variable refers to another method on the object, and this is what
saves us from having to prefix same-object methods with “this” or
“self”.
我在这里找到的:Of closures, methods, procs, scope, and Ruby.
具有{msg}的所有这些各种块必须像Proc主体那样工作. define_singleton_method正在获取块并为其提供方法规则.
最佳答案 答案与自我和范围有关
在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 }
闭包抓取的唯一本地绑定是’obj’
这可以通过修改代码来证明:
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的本地绑定值.
如果你想了解更多关于它是如何工作的,我强烈推荐“实用程序员 – 元编程Ruby”你会学到很多关于自我和闭包的知识.
http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Facets/dp/1941222129
– – 编辑 – –
“为什么是”
def p
Proc.new {msg}
结束
不同于
def d2(obj)
obj.define_singleton_method(:say2){msg}
结束
它是不同的,因为块内的自我是不同的.在方法定义“p”中,块可以访问实例变量和方法,而方法“d2”有一个只能访问Object的块.我们可以通过一点点monkeypatching来证明这一点.添加此代码:
class Object
def msg
“再见”
结束