在 變數 中談過,在Ruby中有五種變數,包括區域變數、全域變數、實例變數、類別變數與常數,目前已經談過的有區塊變數、全域變數與常數,在看過 def 定義方法 與 迭代器與程式區塊 後,這邊要來談談區塊變數、全域變數與常數的範圍問題。
全域變數比較不需要討論,全域變數的範圍為整個程式可見,比較要討論的是區塊變數,在Ruby中,區域變數的可見範圍真的就是「區域」,變數在哪個範圍中宣告,就在哪個範圍中可見。例如:
>> x = 10
=> 10
>> def some
>> puts x
>> end
=> nil
>> some
NameError: undefined local variable or method `x' for main:Object
from (irb):3:in `some'
from (irb):5
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
=> 10
>> def some
>> puts x
>> end
=> nil
>> some
NameError: undefined local variable or method `x' for main:Object
from (irb):3:in `some'
from (irb):5
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
上例於some方法外定義了x區域變數(實際上是Object類別本體中的區域變數,之後還會談到),some方法中是看不到該變數的。類似地,
>> def some
>> x = 10
>> def inner
>> puts x
>> end
>> inner
>> end
=> nil
>> some
NameError: undefined local variable or method `x' for main:Object
from (irb):15:in `inner'
from (irb):17:in `some'
from (irb):19
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
>> x = 10
>> def inner
>> puts x
>> end
>> inner
>> end
=> nil
>> some
NameError: undefined local variable or method `x' for main:Object
from (irb):15:in `inner'
from (irb):17:in `some'
from (irb):19
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
some方法中宣告了x區域變數,inner是看不到該變數的。要小心以下:
>> x = 10
=> 10
>> def some
>> x = 20
>> puts x
>> end
=> nil
>> some
20
=> nil
>> x
=> 10
>>
=> 10
>> def some
>> x = 20
>> puts x
>> end
=> nil
>> some
20
=> nil
>> x
=> 10
>>
上例中some中的x指定,其實是建立了新的區域變數,而不是將值指定給some方法外的x變數。
在 變數 中談過,Ruby區域變數有個特性,直譯器只要看到程式碼中有「變數=值」的語句,就會為建立該變數,這會造成有以下的結果:
>> if false
>> a = 10
>> end
=> nil
>> a
=> nil
>> b
NameError: undefined local variable or method `b' for main:Object
from (irb):5
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
>> a = 10
>> end
=> nil
>> a
=> nil
>> b
NameError: undefined local variable or method `b' for main:Object
from (irb):5
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
在上例中,雖然if的區塊不會執行,但直譯器看到a = 10,就會建立a變數,因此之後嘗試顯示a的值,是有a變數但預設為nil,然後b變數是不存在的,因此出現錯誤。
如果在方法外定義常數的話,方法內是可見的:
>> X = 10
=> 10
>> def some
>> puts X
>> end
=> nil
>> some
10
=> nil
>>
=> 10
>> def some
>> puts X
>> end
=> nil
>> some
10
=> nil
>>
如果使用程式區塊,程式區塊外的區域變數,程式區塊中是看得到的:
>> sum = 0
=> 0
>> [1, 2, 3].each do |element|
?> sum += element
>> end
=> [1, 2, 3]
>> sum
=> 6
>>
=> 0
>> [1, 2, 3].each do |element|
?> sum += element
>> end
=> [1, 2, 3]
>> sum
=> 6
>>
如果怕區塊中使用的變數,剛好與區塊外的變數同名,可以特別在分號之後宣告,告知區域中這個變數必須是區域變數:
>> x = 10
=> 10
>> [1, 2, 3].each do |element; x|
?> x = element + 1
>> end
=> [1, 2, 3]
>> x
=> 10
>>
=> 10
>> [1, 2, 3].each do |element; x|
?> x = element + 1
>> end
=> [1, 2, 3]
>> x
=> 10
>>
定義程式區塊時,若區塊參數湊巧與區塊外的區域變數同名,則只會看到區塊參數:
>> sum = 0
=> 0
>> [1, 2, 3, 4, 5].reduce { |sum, element|
?> sum + element
>> }
=> 15
>> sum
=> 0
>>
=> 0
>> [1, 2, 3, 4, 5].reduce { |sum, element|
?> sum + element
>> }
=> 15
>> sum
=> 0
>>
想得知變數是哪個範圍的變數,可以使用defined?方法:
>> x = 10
=> 10
>> X = 10
=> 10
>> defined? x
=> "local-variable"
>> defined? X
=> "constant"
>> defined? xyz
=> nil
>>
=> 10
>> X = 10
=> 10
>> defined? x
=> "local-variable"
>> defined? X
=> "constant"
>> defined? xyz
=> nil
>>