2012-03-12 35 views
5

我想一個局部變量設置爲現有結合注射局部變量綁定

def foo_callback 
    lambda { |name| p name } 
end 
b = foo_callback.binding 

結合沒有任何局部變量來開始:

b.eval("local_variables") # => [] 

設我們設置了原始局部變量綁定:

b.eval("age=30") 

一切正常:

b.eval("local_variables") # => ["age"] 
b.eval("age") # => 30 

現在,讓我們嘗試將非基本局部變量設置爲綁定:

country = Country.first 
b.eval("lambda {|v| country = v}").call(country) 

注:technique設置的變量是從facet寶石借來的。我試着紅寶石1.9安全implementation具有相同的結果。

綁定不反映局部變量country

b.eval("local_variables") # => ["age"] 

我該如何解決這個問題?實質上,我想用一個現有的非原始變量的值在綁定中聲明一個新變量。

我在Ruby 1.8.7上。

+0

結合()是私有的,這樣的結合可以永遠這樣調用:'B = foo_callback.binding' – 7stud 2014-09-09 21:27:43

+0

@ 7stud可以。在ruby控制檯中運行代碼'def foo_callback lambda {| name | p name} end b = foo_callback.binding' – 2014-09-09 22:01:41

回答

5

您在綁定的外部創建country,然後lambda內的country僅在該範圍內有效。爲什麼不eval它,如果你需要注入綁定以及?

更新

嘗試宣告lambda的範圍之外,但裏面的變量綁定的範圍:

b.eval("country = nil; lambda {|v| country = v}").call(country) 
+0

'eval'以字符串作爲參數,所以我無法通過引用傳遞現有變量的值。我使用的代碼非常類似於'facet' gem中使用的代碼:https://github.com/rubyworks/facets/blob/master/lib/core/facets/binding/op_get.rb – 2012-03-12 18:57:55

+0

*方面*在1.9中不工作並不令人鼓舞。綁定在Ruby中非常重要,但我一直髮現,操縱和使用它們的系統只有一個很糟糕的想法。我已經用一個粗略的解決方案更新了我的答案。 – tadman 2012-03-12 19:06:06

+0

當我使用Ruby 1.9安全實現時,獲得了相同的結果:https://github.com/rubyworks/facets/blob/master/lib/core/facets/binding/with.rb#L7 – 2012-03-12 19:08:57

2

這裏的問題是,你正在創建一個新的拉姆達在另一個lambda中,這是創建一個新的範圍。

爲了更清楚起見,綁定'b'將在其範圍內包含函數#foo_callback範圍內的所有局部變量以及第一個lambda中可用的所有局部變量。您創建的第二個lambda是一個新的作用域,因此在該作用域中創建的新局部變量不會在作用域外持久化,除非它們首先在內部作用域之外初始化。

這就是爲什麼你會看到很多人在進入塊之前將局部變量初始化爲零。你也可以做到這一點,它做同樣的事情:

country = country 
{...block that sets country to something non-nil...} 
return country 

實例變量沒有這個範圍的問題,是整個功能的內部和外部的範圍內有效。

例:

b.eval("lambda {|c| @country = c}").call(country) 
b.eval "instance_variables" 

應該工作。

而且,有人打我的答案,而我寫這篇:)