這是因爲在你的add_one
函數中,你並沒有在函數外部操縱相同的i
變量。
讓我試着解釋一下。在Ruby中,你處理的是一般可變的對象(值得注意的例外是數字,true
,false
和nil
)。變量是指向這樣一個對象的指針。多個變量可以指向同一個對象。
a = 123
b = a
現在a
和b
指的是相同的對象。如果您將新對象分配給a
或b
之一,則它們將再次引用不同的對象,同時仍保留該名稱。
你上面的是局部變量。這些僅在範圍內有效,主要是方法的持續時間。如果你創建一個新的局部變量(通過賦值給它),它只會在方法持續時間內有效,並且在離開方法後的某個時候會被垃圾回收。
現在正如我上面所說,Ruby中的大多數對象都是可變的,這意味着您可以在保留變量指針的同時更改它們。一個例子是將一個元素增加到數組:
array = []
array << :foo
現在array
變量仍然會引用它得到了與初始化相同的陣列對象。但是你已經改變了這個對象。如果你將一個新的數組分配array
變量像
array = [:foo]
它看起來像同一個對象,但實際上,它們是不同的(你可以驗證來檢查每個對象的object_id
方法。如果是同樣的,你指的是相同的對象)
現在,當你在add_one
方法做i += 1
時,實際上是運行i = i + 1
將變量i設置爲在本地方法範圍的新值。你實際上並沒有改變i
變量,而是在本地方法範圍內爲它分配一個新值。這意味着您的外部範圍名爲i
的變量(即開始/結束塊)將引用與您的add_one
方法中的變量i
不同的對象。這是因爲雖然他們有相同的名字,但他們有不同的範圍。內部作用域始終掩蓋外部作用域,因此當您在不同作用域中具有相同名稱的變量時,它們不會以任何方式干涉(在處理實例或類變量時會發生變化)
不幸的是,正如我上面所說,數字是不可改變的。你不能改變它們。如果你給一個變量賦一個新的數字,它就是一個新的對象。因此,您不能將指向另一個作用域中某個數字的變量的值更改爲更改該值的代碼。
爲了規避這個問題,可以從您的函數返回一個值,並明確地將其分配給您的i
變量在外部範圍這樣
i = 0
def add_one(i)
i+=1
puts "FUNCTION:#{i}"
return i
end
i = add_one(i)
或者你可以使用實例變量的對象是這樣
class Foo
def initialize
@i = 0
end
def add_one
@i += 1
end
def do_something
begin
puts "BEGIN:#{@i}"
raise unless @i>5
rescue
add_one
puts "RESCUE:#{@i}"
retry
end
end
end
# create a new object and run the instance method
Foo.new.do_something
感謝您的詳細解釋 - 我現在明白了很多! –