2013-10-11 43 views
8

我想知道是否有一種方法可以讓我在當前的上下文中動態定義一個以前未定義的變量。例如:在Ruby中,有沒有辦法在當前上下文中動態定義局部變量?

foo # => NameError: undefined method or local variable ... 
# Some method call which sets foo = 1 in the local context 
foo # => 1 

換句話說,考慮到foo是不確定的,我正在尋找它可以讓我定義的局部變量foo不使用foo變量(例如,如果我有一些其他的變量bar任何代碼其值是:foo,我不得不依靠它來設置foo的值)。

看來eval('foo = 1')eval('foo = 1', binding),或在紅寶石2.1,binding.local_variable_set(:foo, 1)都等同於:

1.times do 
    foo = 1 
end 
換句話說

,他們在當地環境的背景設定foo,使得除此之外無法訪問價值。

是我想要做的可能嗎?

更新:此問題不是特定於任何特定的局部變量上下文(模塊/類,方法,過程,塊等)。我有興趣明確地知道任何可以或不可以完成的環境。

+0

你試圖解決什麼問題?你試圖做什麼,這可能是紅寶石,但我不認爲這是一件好事。 – phoet

+1

不一樣,但也許'define_method(:foo){1}'是一個選項? – spickermann

+1

我知道它涉及可變範圍,但我不明白你的問題。 – icantbecool

回答

8

似乎Ruby的魔力會提供一種方式,但根據Matz的說法,這隻有在1.8經由eval且僅在某些情況下(即irb)纔有可能。由於1.9,此行爲已取出(「嚴格禁止」):

馬茨自己的重量在這裏:https://www.ruby-forum.com/topic/155673#685906

我從什麼地方,現在紅寶石不能動態地創建本地變量讀。這是真的還是隻是一個錯誤?

局部變量在編譯時被創建,使得在EVAL中定義的本地 變量()不能 的eval的外部訪問。在1.8中,irb和tryruby會逐行編譯,因此 局部變量會從eval()溢出,但在1.9中,嚴格來說,即使在逐行編譯的情況下,也是嚴禁 。

  matz. 

(非不合邏輯替代這裏的人誰願意這樣的事情,但沒有確切的技術狀況的提問者):

使用哈希:

local_hash = {} 

my_vars.each_pair do |k,v| 
    local_hash[k] = v 
end 

puts local_hash['foo'] 
#=> 'baz' 
+0

如果您將答案更新爲「不,無法完成」並提供Matz參考,我很樂意接受它。這個假設除了'eval'不可能實現之外,沒有其他的方法可以根據Matz對編譯時創建的局部變量的解釋。 –

+1

不幸的是,我不能這樣做......我只知道馬茨的解釋,但不能確切地告訴你,因爲它已經通過'eval'停止了,它不能通過另一種方法完成(除了運行Ruby 1.8)。所以我可以把門打開,而不是被一個Ruby黑客大師證明是錯誤的:) –

+0

好吧,至少除去「我敢肯定有一種方法」的評論,在這種情況下,我會+1爲Matz參考。 :-)雖然他們可能是一種方式,但我認爲你沒有任何理由「確定」,並且我討厭給任何人虛假的希望。在一個相關的問題上,正如我對這個問題的評論所證明的那樣,我並沒有試圖解決任何潛在的問題;我只是想提高我對語言和核心庫的理解。因此,您提出的涉及哈希的提議並非真正相關,從我的角度來看,最好將其刪除。 –

0

類實例變量會爲你工作嗎?

class Cat 
end 
Cat.instance_variable_set '@last_words', 'meow, meow, me...' 
Cat.instance_variable_get '@last_words' # => "meow, meow, me..." 
Cat.new.instance_variable_get '@last_words' # => nil 

如果不是,請詳細說明上下文以及如何使用本地變量。

+1

我的問題與本地變量所在的位置無關(類,方法,塊,等等)。根據我之前對這個問題的評論,我沒有想要解決的問題。我只是提出一個關於與局部變量聲明相關的語言和核心庫的問題,以便更好地理解。 –

2

在創建局部變量本身的情況下,確實有一些困難需要克服,但動態分配仍然沒有問題。

>> my_lv = 0 
=> 0 
>> instance_eval("#{'my_lv'} = 42") 
=> 42 
>> my_lv 
=> 42 

所以,簡單地從一個收集輸入創建(從gets,chomped或剝離的需要,它會很自然地結束了作爲一個字符串),並呼籲它to_sym和東西新的符號爲local_variables和eval遠...

>> local_variables << :my_created_lv 
=> [:my_lv, 
:__, 
:_, 
:_dir_, 
:_file_, 
:_ex_, 
:_pry_, 
:_out_, 
:_in_, 
:my_created_lv] 
>> 

然後你把你轉換爲符號,並在上面顯示的代碼分配給聚集串,和eval它獲得的價值。

>> eval :my_lv.to_s 
>> 24 

正如在另一個答案中指出的,我無法在Pry或IRB之外輕鬆地複製此內容。

在未來的Ruby版本中,這已經發生了變化,因爲Matz已經移除並努力使其不再能夠發生。

+0

我在詢問變量尚未定義的情況。變量已經定義並且您只是想要更改該值沒有問題。 –

+0

這就是爲什麼我在內插中使用了一個字符串。其餘的是學術。 – vgoff

+0

只能在REPL中工作。 :( – vgoff

相關問題