From: rubikitch Date: 2005-01-13T17:23:05+09:00 Subject: [ruby-list:40529] Re: procの動作について(質問) From: "Hisashi Yahata" Subject: [ruby-list:40526] procの動作について(質問) Date: Thu, 13 Jan 2005 16:38:47 +0900 るびきちです。 > しかし、通常のサブルーチンのようにどこに記述してもよいのではないことがわかり > 始め、さらに単純化すれば、次の二つのように、動作が異なることに気付きました。 > Procの動作をどのように考えればよいのかどなたか教えてください。よろしくお願い > します。 Rubyの変数はデフォルトではローカル変数なので、 「スコープ」という問題があります。変数名の先頭が $ならグローバル変数、 @ならインスタンス変数、 @@ならクラス変数です。 また、大文字で始めると定数になります。 以下リファレンスマニュアルからの引用。 ローカル変数 Local Variable ある範囲内でのみ参照可能な変数。その範囲をスコープと呼ぶ。 Rubyのス コープは □ プログラム全体 □ クラス・モジュール定義 □ メソッド定義 □ ブロック で、『ブロックだけは外側のスコープのローカル変数もアクセスできる。』ロー カル変数の有効範囲はスコープでの最初の代入が現れた場所からスコープの 終りまでである。有効範囲は静的に決まり、実際に実行されるかどうかは関 係ない。 > 問題点: (A)では、beginでaを定義し、prで内容を変換したつもりでも、変換さ > れない。 >       しかし、(B)では、prによってaの内容を3に変更される。 これもスコープで説明できます。 > #====(A)======== > pr=proc{ a=2 } # ブロックローカルのa(別物!) > begin > a=1 # ここでローカル変数aを初期化。aのスコープが始まる > pr.call # ブロックローカルのaは別物なので影響なし > end > pr2=proc{ p a } # このaはローカル変数のa > pr2.call #=>1 pr=の時点でまだローカル変数aは定義されていません。 procブロックの中のaは「ダイナミックローカル変数」でブロック内のみ有効な変数です。 そのため、a=1のaとは別物です。 これもリファレンスマニュアルより引用すると・・・ ダイナミックローカル変数 Dynamic Local Variable ローカル変数の一種。Rubyのローカル変数はスコープが静的に決まるためコ ンパイル時に変数が作成されるが、ダイナミックローカル変数は、実行の都 度変数が作成される。『ブロックの中で初めて代入されたローカル変数はダイ ナミックローカル変数となり、そのスコープはブロックの中だけとなる。』こ れは、Thread 毎に独立した変数を持つためにある。 (A)のスクリプトで期待した動作をさせたいならば、 先頭(pr=の前)に a=0 などと適当な値を入れて初期化しましょう。 こうしておけば、aのスコープは最初から最後まで続いています。 スコープの法則の 『ブロックだけは外側のスコープのローカル変数もアクセスできる。』 というのがポイントです。 a=0 # ローカル変数aを初期化。aのスコープが始まる。 pr=proc{ a=2 } # このaはローカル変数のa # でも実行していないのでaの現在の値は0 begin a=1 pr.call # ここでaの値は2に更新される end pr2=proc{ p a } # ここでもaは2 pr2.call #=>2 > #====(B)========= > a=1 > pr=proc{ a=3 } > pr.call > pr2=proc{ p a } > pr2.call #=>3 この場合はローカル変数aのスコープが最初から続いているので、 proc内のaもこのローカル変数となっています。 procは外側のローカル変数にもアクセスできるのがメソッド(関数)との大き な違いです! るびきち☆ http://www.rubyist.net/~rubikitch/ ←Ruby大衆化計画@移転