変数のスコープ

では、AWKにおける変数のスコープについて一発!!

変数のスコープとは、その変数の有効範囲のことを言います。
難しいことはありません。そのルールは以下の通り単純ですよ・・・

  1. 関数で定義した引数名は、その関数内のみ有効な変数である。
  2. それ以外の変数はすべての範囲で有効となる。
すなわち引数定義した変数はその関数内のみ有効なローカル変数で、その他はすべてグローバル変数となります。
引数名が関数外の変数名と一致していても問題ないのです。

余談ですが、以上のことからAWKの引数は「値渡し」であることが分かります。
「値渡し」とは、変数の内容を関数の引数にコピーすることです。他に変数のポインタを関数に渡す「参照渡し」があります。
AWKでは「参照渡し」はできません。その場合は、管理が面倒ですがグローバル変数として扱えば良いでしょう。
なお、AWKでは配列変数名を引数とすると「参照渡し」となります。当然と言えば当然ですが・・・
渡された配列変数を関数内部で変更すると、渡した側の配列変数も変化します。ご注意ください!!

それではスコープの確認実験をしてみましょう。
以下のようなスクリプトを作り、「scope.awk」と言うファイル名で保存します。
BEGIN {
  a = b = c = d = 0;
  d = test(1, 2);
  print "a=" a, "b=" b, "c=" c, "d=" d;
}

function test(a, b) {
  a++;  b++;
  c = a + b;
  return c;
}
BEGINブロック第1行目は、各変数を 0 で初期化しています。
第2行目は、引数として 1 および 2 を与えて関数を呼び出し、結果を変数 d に代入しています。
第3行目はそれぞれの変数の値を表示させています。

関数 test の第1行目は、引数をそれぞれインクリメント(1 を加算)しています。
第2行目はそれぞれインクリメントした結果を加えて変数 c に代入しています。
第3行目は加算結果を関数の外に返します。

次にこのスクリプトを実行させるためのバッチファイルを作りましょう。
以下の通りエディタで作成して、「scope.awk」と同じディレクトリに「scope.bat」と言うファイル名で保存してください。
このディレクトリにはAWK実行ファイルである gawk.exe もコピーしておいてください。
@echo off
gawk -f scope.awk
pause
「scope.bat」をダブルクリックして起動させましょう。
コマンドプロンプトウィンドウが開き、以下のように表示されるでしょう。
a=0 b=0 c=5 d=5
続行するには何かキーを押してください . . .
この結果からわかることは・・・
  1. 関数内の変数 a、b をインクリメントしているにも関わらず、関数外の変数 a、b は変化しない。引数は関数内のローカル変数である。
  2. 引数として与えられた値+1を加算した値が関数から返され、変数 d に代入されている。
  3. 関数内で代入された変数 c は関数外の変数 c でも同じ代入値となる。変数 c はグローバルである。これが問題!
・・・です。関数内でグローバル変数を使ってしまった悪い例です。
何かのキーを押すとコマンドプロンプトウィンドウは閉じられます。
それでは、関数を改造してみましょう。
BEGINブロックはそのままにして、下記のように関数の引数に c を追加するだけです。
function test(a, b, c) {
  a++;  b++;
  c = a + b;
  return c;
}
実行結果は・・・
a=0 b=0 c=0 d=5
続行するには何かキーを押してください . . .
・・・となり、グローバグ変数 c は 0 のままです。ローカル変数と同名の変数でもグローバル変数に影響することはありません。

大きな関数を修正するとき、ローカル変数の管理をしっかりしないととんでもないバグを生みだし、収拾に時間がかかること間違いなし!!
以上、変数のスコープを意識しながら関数を作成しましょう・・・というお話でした。。。

<-->

戻る