Ruby 使用手冊

區域變數 Local variables

區域變數 (local variable) 以小寫字母或底線字元 (_) 開頭, 與全域變數及實例變數不同,區域變數初始化前並沒有 nil 值:

ruby> $foo
   nil
ruby> @foo
   nil
ruby> foo
ERR: (eval):1: undefined local variable or method `foo' for main(Object)

第一次指派予區域變數的工作,其性質就像是宣告。如果你使用一個沒有初始化的區域變數,Ruby 直譯器可能會以為你指的是一個假值 (bogus variable),例如可能是拼錯方法名稱。就會出現上面看的錯誤訊息。

一般來說,區域變數的作用域包括

下例中,defined? 是檢查識別符 (identifier) 有否定義的運算子。若已定義,就會傳回該識別符的描述,否則就傳回 nil。如你所見,bar 的作用域位於迴圈內;若迴圈結束,bar 就變成未定義了。

ruby> foo = 44; puts foo; defined?(foo)
44
   "local-variable"
ruby> loop{bar=45; puts bar; break}; defined?(bar)
45
   nil

位於同一作用域的程序物件(編註:即 Proc.new 和 lambda 裡),會共享該作用域內的所有區域變數。因此,區域變數 barmain、程序物件 p1p2 所共享:

ruby> bar=nil
   nil
ruby> p1 = Proc.new {|n| bar=n}
   #<Proc:0x8deb0>
ruby> p2 = Proc.new {bar}
   #<Proc:0x8dce8>
ruby> p1.call(5)
   5
ruby> bar
   5
ruby> p2.call
   5

請注意,開頭的 "bar=nil" 不能省略,它可確保 bar 的作用域涵蓋 p1p2。否則 p1p2 會使用各自的區域變數 bar,呼叫 p2 時,就會出現 "undefined local variable or method"(未定義區域變數或方法)錯誤。我們可以寫 bar=0,但使用 nil 對於之後看程式碼的人則比較禮貌。這樣就能夠清楚的顯示你只是設定作用域,因為所指派的值並無任何意義。

程序物件具有一項強大的功能,就是能夠以引數的方式傳遞:共享的區域變數就算不在原有的作用域,仍然保持有效。

ruby> def box
    |   contents = nil
    |   get = Proc.new {contents}
    |   set = Proc.new {|n| contents = n}
    |   return get, set
    | end
   nil
ruby> reader, writer = box
   [#<Proc:0x40170fc0>, #<Proc:0x40170fac>]
ruby> reader.call
   nil
ruby> writer.call(2)
   2
ruby> reader.call
   2

Ruby 對於作用域非常聰明, 從例子中就能夠證明如此,contents 變數由 readerwriter 所共享。但我們也能利用以上定義的 box,製造多重的閱讀器-寫入器 (reader-writer) 對,每對閱讀器-寫入器可共享 contents 變數,而且對與對之間並不會互相干擾。

ruby> reader_1, writer_1 = box
   [#<Proc:0x40172820>, #<Proc:0x4017280c>]
ruby> reader_2, writer_2 = box
   [#<Proc:0x40172668>, #<Proc:0x40172654>]
ruby> writer_1.call(99)
   99
ruby> reader_1.call
   99
ruby> reader_2.call  # 該 box 中尚無任何內容
   nil

這種程式設計也具有物件導向框架。box 方法的作用就像類別,getset 就像是方法(那些不是真正的方法名稱除外,他們會隨著不同的 box 實例而不同),而 contents 則是單獨的實例變數。當然,使用 Ruby 認可的類別框架,可編寫出更容易閱讀的程式碼。

Copyright (c) 2005-2008 Mark Slagell,中文翻譯 Ruby Taiwan 社群

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license is included in the section entitled "GNU Free Documentation License."