「Rubyには参照渡ししかない」とだけ覚えていたことから、生じていた思い込み:
×メソッドの引数を介して、グローバル変数の値は変えられる
これは間違い。
以下が正しい:
- 代入演算子= は、参照先を変更する(だけの)ためのものである
- メソッドは、オブジェクトに対するメッセージである
- メソッドの機能の一つには、オブジェクト内部のフィールドの値を変更することがある
- メソッド定義の仮引数は、メソッドのスコープのローカル変数である
実験
以下のようなt_f, t_f2, t_f3 のメソッドがあるとする:
irb(main):022:0> def t_f( a ) irb(main):023:1> a='t_f' irb(main):024:1> end => nil irb(main):029:0> def t_f2( a ) irb(main):030:1> a.push('bar') irb(main):031:1> end => nil irb(main):036:0> def t_f3( a ) irb(main):037:1> b=a irb(main):038:1> b.push('t_f3') irb(main):039:1> end => nil
メソッド t_f のテスト
irb(main):025:0> a="boo" => "boo" irb(main):026:0> t_f( a ) => "t_f" irb(main):027:0> a => "boo"
グローバル・スコープの変数 a の参照が、メソッド t_f の仮引数 a にコピーされる
(この時点で t_f の仮引数a の参照先は、オブジェクト"boo"である)
メソッド t_f の仮引数 a の参照先が、文字列オブジェクト "t_f" に、変更される
メソッド t_f を抜けたので、メソッド t_f の仮引数 a は破棄される
��グローバル・スコープの変数 a の値=参照先は、 "boo" のままであることが、確認される)
メソッド t_f2 のテスト
irb(main):028:0> b=['boo'] => ["boo"] irb(main):033:0> t_f2( b ) => ["boo", "bar"] irb(main):034:0> b => ["boo", "bar"]
グローバル・スコープの変数b の参照が、メソッドt_f2の仮引数a にコピーされる(この時点でt_fの仮引数a の参照先は、オブジェクト["boo"]である)
メソッドt_f2の仮引数a に、メッセージpush("bar")が渡され、仮引数a の参照先のオブジェクトは["boo", "bar"]に、変更される
メソッドt_f2 を抜けたので、メソッドt_f2 の仮引数a は破棄される
��グローバル・スコープの変数b の値=参照先のオブジェクトの値は、["boo", "bar"]と変更されていることが、確認される)
メソッド t_f3 のテスト
irb(main):042:0> b=["boo", "bar", "bar"] => ["boo", "bar", "bar"] irb(main):043:0> t_f3( b ) => ["boo", "bar", "bar", "t_f3"] irb(main):044:0> b => ["boo", "bar", "bar", "t_f3"]
グローバル・スコープの変数b の参照が、メソッドt_f3の仮引数a にコピーされる
(この時点でt_fの仮引数a の参照先は、オブジェクト["boo", "bar", "bar"]である)
メソッドt_f2のローカル変数b の参照先は、仮引数a の参照先に設定される
メソッドt_f2のローカル変数b の参照先に、"t_f3"がpushされ、オブジェクト["boo", "bar", "bar", "t_f3"]に、変更される
メソッドt_f2 を抜けたので、メソッドt_f2 の仮引数a 、ローカル変数b は、ともに破棄される
��グローバル・スコープの変数b の値=参照先のオブジェクトの値は、["boo", "bar", "bar", "t_f3"]と変更されていることが、確認される)