このルビー(2.2.3p173)コード:Rubyのdefine_singleton_methodのクロージャはどのように機能しますか?
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に違いは何ですか? define_singleton_methodに渡されたものを除いて、すべてのブロックがmsgを参照するのはなぜですか?
更新:
私はそれがこれに尽きると思う:
PROC本体
Rubyは procの内部で自由変数に遭遇したときにことを意味し、Lispや のJavaScriptの関数のようなレキシカルスコープを持っていますその値は、procが と定義されたコンテキスト内で解決されます。これがクロージャーを可能にするものです。しかしながら、方法は異なっている、 しかし。メソッドのコンテキストは、それらがバインドされているオブジェクトです。 Rubyでメソッド本体の空き変数が見つかると、 変数がオブジェクトの別のメソッドを参照しているとみなします。これは が "this"または "self"で同じオブジェクトメソッドの接頭辞を取らないようにします。
これは私がここに見つけた:Of closures, methods, procs, scope, and Rubyです。
{ msg }
のこれらのさまざまなブロックはすべて、Proc本体として機能する必要があります。 define_singleton_method
はブロックを取得し、メソッドのルールを与えています。
私はバウンド= MSGは見るために閉鎖のためのバインディングを作成することを理解しています。しかし、これはProc.new {msg}とどう違うのですか?このブロック{msg}はmsgをどのように見ますか?このブロック{msg}はありません。 –
私は答えを推測するつもりです:マップに渡されたProc、lambda、block内のこのブロック{msg}はself#msgに解決されなければならず、define_instance_methodのselfが明らかにobjであるインスタンスに設定されていなければなりません。私はこれをさらに調べるためにあなた自身の考えを試してみましょう。ありがとう。 –
私は私の答えがあると思う。私の質問に私の編集を参照してください。 –