PowerShell覚え書き
お題
PowerShell2.0からクロージャ機能があるとのことで、アキュムレータを作ってみました。function Accum([int]$init) { $i=$init { $script:i++; $i}.GetNewClosure() # return { $script:i++; return $i}.GetNewClosure() #ちゃんとreturnをつけるとこうなる。 } "`$i=" + $i #スクリプトスコープ "Get Accumlator init=100" $a=Accum 100 "call by `&" 1..3|%{ &$a } "`$i=" + $i #スクリプトスコープ "set `$i = 1000" $i=1000 "call by `&" 1..3|%{ &$a } "call by `." 1..3|%{ . $a } "`$i=" + $i #スクリプトスコープ
実行結果は以下の通り。
-
$i=
Get Accumlator init=100
call by &
101
102
103
$i=
set $i = 1000
call by &
104
105
106
call by .
107
108
109
$i=1000
メモ
- クロージャ作成方法はご覧のとおりスクリプトブロックのGetNewClosure()メソッドの呼び出しです。
- クロージャのブロック内で「$script:i++」とスコープを指定しているのは親ブロック側の変数を変更してやるためです。ただし、本当は親ブロックの変数なのでスクリプトスコープにする必要はないのですが、Set-Variableでやるのも面倒でこうしました。実行結果の通りスクリプト内で$iに値を設定しても影響を受けないので、クロージャ内の環境に保持されているはずです。
- 「$a=Accum 100」で変数$aにクロージャを代入(変数を束縛?)して、その後そのクロージャを呼び出していますが、PowerShellの場合にその呼び出し方は2種類あるようです。
- 「&$a」 ヘルプのabout_functionsにはこちらが書かれていて、ネット上もそのようにやっている例が散見されました。一般的にはこちらを使用することが多いようです。(追記:&はローカルコンピュータ上のInvoke-Commandと同義で、スクリプト ブロックの文字列をコマンドとして評価または実行する)
- 「. $a」 いわゆるソース呼び出しなのですが、こちらも確かにクロージャとして動作しています。また、こちらの呼び出し方の場合にはクロージャのスコープが親スコープと同一となるようで上述したscriptスコープの指定がなくても動くみたいです。ソース呼び出しの場合にはスコープが変わるというのは言われてみればそうかもしれません。でも、クロージャのスコープ自体は不思議なものですね。
とりあえずクロージャが動くようなので、どこかでもう少し別のサンプルを作りたいと考えています。
0 件のコメント:
コメントを投稿