2015-11-24 121 views
5

考慮以下兩段ruby代碼片段。Ruby中的變量範圍

puts "One" 
if false 
    d = 1 
end 
puts "Two" 
puts d 
puts "Three" 

這將打印以下

One 
Two 

Three 

現在,請考慮以下

[].each do |i| 
    flag = false 
end 
puts "Two" 
puts flag 
puts "Three" 

這給出了以下

Two 
'<main>': undefined local variable or method 'flag' for main:Object (NameError) 

爲什麼在第一種情況下空白打印和第二ca是否引發錯誤?

感謝

+0

的[我不明白紅寶石局部範圍]可能的複製(http://stackoverflow.com/questions/4154864/ i-dont-understand-ruby-local-scope) –

+1

塊創建一個新的作用域,因此在該作用域之外的變量未被定義。 '如果'另一方面 - 不。當解釋器看到一行代碼將賦予一個變量值時,它會確保它首先被定義並用'nil'初始化它。這也是爲什麼'foo = bar'會給你一個錯誤,而'baz = baz'不會。 – ndn

+2

在第二種情況下,'flag'變量是該塊的範圍,因此在外面不可見(http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/localvars.html)。在第一種情況下,即使代碼塊沒有執行,該變量也會被定義 - 這一部分我不確定 - 可能是Ruby解釋器將其標記爲已定義 –

回答

5

區別在於if塊實際上並不像其他語言(如Java)中的單獨範圍。在if塊中聲明的變量與周圍環境具有相同的範圍。現在,在你的情況下,那個if塊實際上不會被執行,所以你通常會認爲d是未定義的(導致你在第二個例子中得到同樣的錯誤)。但是ruby有點「傻瓜」,因爲解釋器在它看到它的時候會設置一個帶有該標籤的變量,而不管它是否被實際執行,因爲它基本上不知道該分支是否確實會執行。這在"The Ruby Programming Language" David Flanagan着和松本行弘解釋(不能複製粘貼文本,添加截圖代替): enter image description here

.each循環的情況下,do...end你寫的其實是一個block ,它確實有它自己的本地範圍。換句話說,塊內聲明的變量僅在該塊的本地。

但是,塊「繼承」了它們聲明的環境的範圍,因此您可以做的是在.each迭代塊之外聲明flag,然後該塊將能夠訪問它並設置其值。請注意,在你給出的例子中,這不會發生,因爲你試圖迭代一個空數組,但至少你不會再收到錯誤。

一些額外閱讀:

+1

非常感謝您的詳細解答。它非常有幫助:) – Jim

+0

@Jim我的榮幸,很高興它有所幫助。 –

2

在Ruby中,當你做一個賦值給一個變量(在你的情況下,它d)在if語句的假分支的任何地方,它宣稱,除非方法d=定義這個變量。基本上b = bla-bla-bla在False分支使這個:b = nil

當您在空數組上使用塊時,什麼都不會發生。並且如果數組不爲空可變仍然是本地的塊的當前迭代,除非它是外塊範圍定義,例如:

[1,2,3,4].each do |i| 
    a=i 
end 
puts a 

NameError: undefined local variable or method `a' for main:Object

a=1 
[1,2,3,4].each do |i| 
    a=i 
end 
puts a 

4

您也有一個選擇使用a作爲塊內的本地的,如果它已被前面所定義:

a=1 
[1,2,3,4].each do |i; a| 
    a=i 
end 
puts a 

1

+0

感謝您的解釋以及:) – Jim