前のページ 次のページ 目次

2. 変数と定数

2.1 ローカル変数のスコープはどのように決められていますか

トップレベル,クラス(モジュール)定義,メソッド定義のそれぞれで 独立したスコープになっています.ブロック内では,新たなスコープが 導入されるとともに,外側のローカル変数を参照できます.

ブロック内が特別になっているのは,Threadや手続きオブジェクトの 中で局所化するためです.

whileuntilforは制御構造であり,新しいスコープを 導入しません. loopはメソッドで,後ろについているのはブロックです.

2.2 ローカル変数はいつ参照可能になるのでしょうか

Rubyスクリプトは,Rubyインタプリタに実行させようとすると, まず最後まで一度読みこまれ,構文解析されます.構文上問題が生じなければ, 構文解析で作られた構文木が最初から実行に移されます.

ローカル変数が参照可能になるのは,この構文解析の時にローカル変数への 代入文が見つかった時です.

for i in 1..2
  if i == 2
    print a
  else
    a = 1
  end
end
test.rbというファイルにいれて,このスクリプトを実行すると,

test.rb:3: undefined local variable or method `a' for
   #<Object:0x40101f4c> (NameError)
      from test.rb:1:in `each'
      from test.rb:1
ということで,iが1の時は,エラーが起こらず,iが2になった時に エラーが起こります.構文解析の時には,最初のprint aが実際には aへの代入が行われてから実行されるというところまで解析されず, この文を構文解析する時までにaへの代入文が現われていないので, ローカル変数は参照されません.実行時にはaというメソッドが ないか探しますが,これも定義されていないのでエラーになります.

逆に,次のスクリプトは,エラーになりません.

a = 1 if false; print a
# ->nil
ローカル変数のこのような振舞いに悩まされないためには,ローカル変数が 参照される文より前に,a = nil といった代入文を置くことがすすめられて います.こうすると,ローカル変数の参照が速くなるというおまけもついて います.

2.3 定数のスコープはどのように決められていますか

クラス/モジュールで定義された定数は,そのクラス/モジュールの中で 参照できます.

クラス/モジュール定義がネストしている場合には,内側のクラス/モジュール から外側の定数を参照できます.

またスーパークラス及びインクルードしたモジュールの定数を参照できます.

トップレベルで定義された定数は,Objectクラスに追加されますので, すべてのクラス/モジュールから参照できます.

直接参照できない定数は,::演算子を使って,クラス/モジュール名を 指定することにより参照できます.

2.4 変数や定数にメソッドを適用すると予期しないことが起こりますが

次のような例でしょうか.

A = a = b = "abc"; b << "d"; print a, " ", A
# ->abcd abcd
変数や定数への代入は,オブジェクトを後でその変数や定数で参照する ために用いられます.変数や定数にオブジェクトそのものが代入されて いるのではなく,オブジェクトの参照を保持しているだけです.変数は, この参照を変更して異なるオブジェクトを参照するようにすることが できますが,定数では一度保持した参照を変更することができません.

変数や定数にメソッドを適用すると,そのメソッドは,変数や定数が 指しているオブジェクトに適用されます.上の例では,<<というメソッドが オブジェクトの状態を変えてしまうために,「予期せぬ」結果が生まれて います.オブジェクトが数値の場合には,数値の状態を変えるメソッドが ないため,このような問題は生じません.数値にメソッドを適用した時には 新しいオブジェクトが返されます.

この例では,文字列で示しましたが,配列やハッシュなど,オブジェクトの 状態を変更するメソッドを持っているオブジェクトでも同様のことが起こり 得ます.

2.5 Fixnumtruenilfalseが即値だということですが,参照との違いは何ですか

特異メソッドを定義できないという制限がある他は,即値と参照の違いは 特にありません.

2.6 定数は変更されませんか

定数があるオブジェクトを指しているとき,別のオブジェクトを指すように はできませんが,そのオブジェクトが破壊的メソッドを持っていれば, オブジェクトの内容は変更できます.


前のページ 次のページ 目次