トップ回答者
PowerShellのスクリプト変数のCopyOnWriteバグ?

質問
-
次のソースを実行する。
$gv=9686
$funcs = @(
{
echo "GlobalOnRead"
$lv = $gv
Write-Output $lv
}
,
{
echo "CopyOnWrite"
$lv = $gv
$lv += 5050 - 9686
Write-Output $lv
}
,
{
echo "LocalOnWrite"
$lv = $gv
$gv += 5050 - 9686
Write-Output ([String]$lv + ":" + $gv)
}
)
for($i = 0; $i -lt $funcs.length; $i++)
{
Write-Output $funcs[$i].invoke()
}
結果
GlobalOnRead
9686
CopyOnWrite
5050
LocalOnWrite
9686:-4636本来は次になるべきでは
GlobalOnRead
9686
CopyOnWrite
5050
LocalOnWrite
9686:5050原因はCopyOnWriteの実装に誤りがあり、ローカル変数領域を確保後に、グローバル変数をコピーしていないのではないかと思います。
回答
-
コメントを追加します。
上記の動作はPowerShell 3.0での仕様変更によるものでした。
リリースノートに以下の変更が明記されていました。
Read/Modify/Write operators no longer use dynamic scoping for the Read operation. Also, compound equality operators (including +=, -=, *=, %=, ++, --) do not use dynamic scoping. The variable is always in the current scope.
コード例としては、
https://github.com/nightroman/PowerShellTraps/tree/master/Basic/Compound-assignment-operators
の方のサンプルを見ていただくとわかりやすいかと思います。
- 回答の候補に設定 Hebikuzure aka Murachi AkiraMVP 2016年12月22日 15:02
- 回答としてマーク nwpfh 2019年1月27日 3:56
すべての返信
-
おはようございます。
PowerShellのバージョンによってはこの挙動がちょっと異なる様で、PowerShell 2.0だと期待した動作をしますね。
PowerShell 3.0から動作が変わっている様ですが、これが仕様変更なのかスコープのバグなのかはちょっとわかりません。
現状、新しいPowerShellでは最後のLocalOnWriteのスクリプトブロックについて、
$gv += 5050 - 9686
の部分はスコープを明示していないため、ローカルスコープ
$gv += 5050 - 9686 # ↓ $local:gv += 5050 - 9686 # ↓ $local:gv = $local:gv + 5050 - 9686
として扱われています。
このため-4636を返してます。
なお、
$lv = $gv
については、この時点でローカルな$gvは未定義なため、上位スコープの変数を参照して9686の値を取得しています。
期待する動作をさせるためには、
$gv = $gv + 5050 - 9686
と+=演算子を展開するしかない様です。
※バージョンによる挙動の差異を発見したのでコメントを編集しました。
- 編集済み stknohg 2016年12月22日 3:22
- 回答の候補に設定 Hebikuzure aka Murachi AkiraMVP 2016年12月22日 15:02
-
コメントを追加します。
上記の動作はPowerShell 3.0での仕様変更によるものでした。
リリースノートに以下の変更が明記されていました。
Read/Modify/Write operators no longer use dynamic scoping for the Read operation. Also, compound equality operators (including +=, -=, *=, %=, ++, --) do not use dynamic scoping. The variable is always in the current scope.
コード例としては、
https://github.com/nightroman/PowerShellTraps/tree/master/Basic/Compound-assignment-operators
の方のサンプルを見ていただくとわかりやすいかと思います。
- 回答の候補に設定 Hebikuzure aka Murachi AkiraMVP 2016年12月22日 15:02
- 回答としてマーク nwpfh 2019年1月27日 3:56