2010年6月21日月曜日

◆スコープ

Powershellのスコープは若干判りづらい。(気がする)

以下のスクリプトを見て、3つのWrite-Hostがそれぞれ何を出力するか判るだろうか。

function testFunc($a){
    Write-host $a
    $a +=1
    Write-host $a
}

$a = 123
testFunc $a
Write-Host $a


結果は、
123
124
123

testFuncは子スコープになっているので、そこでの変数の更新は親スコープに反映されない。
(参照は可能なところがやっかい。子スコープにコピーされるイメージなのだろうか)

外出しの関数であれば戻り値で受け渡すのが良いと思うが、同一スクリプト内であれば直接更新したいこともあるだろう。
さしあたって引数で渡してみる。

function testFunc($a){
    Write-host $a
    $a +=1
    Write-host $a
}

$a = 123
testFunc $a
Write-Host $a


っが、結果は変わらない。きっと値渡しなのだろう。
参照渡しはっと、

function testFunc([ref]$a){
    Write-host $a.value
    $a.value +=1
    Write-host $a.value
}

$a = 123
testFunc ([ref]$a)
Write-Host $a


こんな感じっぽい。
[ref]をつけるだけなら良いが、やけに面倒。
こんなことなら戻り値もらったほうが・・・。

別の方法を調べていると、どうやら変数にスコープをつけてやれば良いようだ。

function testFunc{
    Write-host $a
    $script:a +=1
    Write-host $a
}

$a = 123
testFunc
Write-Host $a


このスコープには以下の種類がある。
global(全体に有効)
script(スクリプト内で有効)
local(現在のスコープとその子スコープで有効)
private(現在のスコープでのみ有効)

globalとscriptの仕様を確認するために以下のようなスクリプトを作ってみた。

#funcScriptGlobalACounuUP.ps1
function test{
    $global:a += 1
    $script:a += 1
}

$script:a = 1
test
$script:a

これを実行するとこんな感じ、

PS>$a = 2
PS>funcScriptGlobalACounuUP.ps1
2
PS>$a
3

これは予想通りの結果。

しかし、このスクリプトをコマンドラインに張り付けて実行(もしくはISEで開いて実行)するとこんな結果になる。

PS>function test{
>>     $global:a += 1
>>     $script:a += 1
>> }
>>
PS>$script:a = 1
PS>test
PS>$script:a
3


先ほどは2と表示された$script:aの値が3と表示されている。

どうやらスクリプトスコープが存在しない環境では$script:aも$global:aも同じものとして扱われるようだ。

このように、スコープとは相対的なもののようなので、その使用に当たっては注意が必要だろう。
特に、ISEでスクリプトを書いて、その場でテストしてOKでも本番環境では違った結果になりうるので必ず本番環境でのテストが必要。

PowerShell: ◆スコープ2

0 件のコメント:

コメントを投稿