関数の内側から外側のスコープの変数にアクセスできるかどうか

Java

Java8ではメソッド内にラムダ式を書くことができるようになったが、 Java7までは、メソッド定義の中に関数を書くことはできない。ただ、メソッド定義の中に内部クラスとそのメソッドを書くことはできる。

その内側のメソッド(内部クラスのメソッド)からは、外側のメソッドの変数を参照することはできるが、変数の書き換えをすることはできない。

Java7までは、その変数が final で指定されている必要がある。

Java8からは、final 指定がなくてもよいが、実質 final である必要がある。つまり、その変数がどこからも書き換えられていないことが必要である。

Java8からはラムダ式を書けるが、外側の変数を書き換えられないのは同じである。

PHP

function builder(){
    $i = 0;
    return function() use (&$i) {
        echo "$i\n";
        $i++;
    };
}

$f1 = builder();
$f2 = builder();
$f1(); // => 0
$f1(); // => 1
$f2(); // => 0
$f1(); // => 2

関数の外側のスコープにある変数を参照するには use ($i) のように宣言する必要がある。さらにその変数を書き換えるには use (&$i) のように宣言する必要がある。

上記の例で use (&$i)use ($i) と書くと、$i++ でエラーは発生しないが、書き換えた結果は無視され、4回とも0が出力される。

use を書かなかった場合は $i を参照できないので、 PHP Notice: Undefined variable: i が出力される。

Ruby

def builder
  i = 0
  Proc.new do
    puts i
    i = i + 1
  end
end

f1 = builder
f2 = builder
f1.call # => 0
f1.call # => 1
f2.call # => 0
f1.call # => 2

Procオブジェクトは、その外側の変数を読み書きできる。

JavaScript

関数の中から外にある変数を読み書きできる。

var builder = function(){
    var i = 0;
    return function(){
        console.log(i);
        i = i + 1;
    }
}
var f1 = builder();
var f2 = builder();
f1(); // => 0
f1(); // => 1
f2(); // => 0
f1(); // => 2
このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。