2010年2月8日月曜日

PowerShellの変数のスコープ、その2

前回の続き。

PowerShellにおけるスコープとは何ぞや、という事ですが、
スクリプトブロックや関数の間で、
どの変数が見えて、どの変数が見えないか、
という事を表現するための概念のようです。

たとえば:
powershellのコンソール画面上で定義した変数は、
コンソールから呼び出した関数内でどのように認識されることになるかとか、
ある関数から別の関数を呼び出した場合に変数はどのように引き継がれるかとか、
関数内にスクリプトブロックを使用する場合に
スクリプトブロック内外で変数はどのように扱われるか、
といったような事を考える上で必要な知識です。

PowerShellの変数のスコープは、全部で4種類存在します。
詳細はいろいろな方がまとめていらっしゃいます。
その中で、ここでは++C++;// 未確認飛行 C(岩永様)
リンクを貼るにとどめます。

今回は、4種類の変数に加え、スコープを明示しない場合
(本エントリー内では「デフォルトスコープ」と記述)も加えた
合計の5種類のスコープの変数について調べてみました。

使用したスクリプト(スクリプトのスコープを確認する):
#変数を消しておく
Remove-Variable -Name "v" -ErrorAction SilentlyContinue
"0:[{0}][{1}][{2}][{3}][{4}]" -f "global", "script", "local", "private", "none"
"0:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
  &{
    "1:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
    &{ 
      #【xxxxxx:】の部分を、いろいろ変えながら遊んでみる。
      #選択肢 → なし、global:、script:、local:、private
      $xxxxxx:v = "a"
      "2:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
      &{ 
        "3:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
         #【yyyyyy:】の部分を、いろいろ変えながら遊んでみる。
        if( $v ) { $yyyyyy:v = "b" }
        "3:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
        &{
          "4:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
         #【zzzzzz:】の部分を、いろいろ変えながら遊んでみる。
         if( $v ) { $zzzzzz:v = "c" }
          "4:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
        }
        "3:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
      }
      "2:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
    }
    "1:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v
  }
"0:[{0}][{1}][{2}][{3}][{4}]" -f $global:v, $script:v, $local:v, $private:v, $v


このコードを、xxxxxx、yyyyyyおよびzzzzzzを変えながら実行した結果、
変数についていくつかの所見が得られたのでまとめておきます。
(あくまで私個人の所見であり、まだMSDN等での裏付けはとっていません)

---
①PowerShellの変数はスタックで実装されている?
 (PowerShellブログにこれを裏付ける記述がある
 子スクリプトブロックに入る時に新しい値がプッシュされ、
 ブロックを出るときにその値がポップされる。
 Get-VariableおよびSet-Variableの両コマンドレットを用いて、
 任意の場所のデータを取得/変更することが可能。
 スタックの起点にはグローバル変数の情報があり、
 スコープを明示することでアクセスできる?

②変数のスコープは、明示的に指定しない限りローカルスコープとなる。

③ローカルスコープで宣言した変数は、同一ブロック内ではプライベートスコープの変数としても参照できる。
 が、混乱を招く恐れがあるのでやらないようにしましょう。

④親ブロックのローカル変数の内容を子ブロックから参照する場合、デフォルトスコープで参照する必要がある。

⑤プライベートスコープの変数は、自身の定義されたブロック内でのみ有効となる。

⑥グローバルスコープの変数の書き換えを実施する場合には、スコープを明示する必要がある。

⑦powershellコンソール上で宣言された変数は、プライベートスコープで宣言しない限りグローバルスコープとなる。

⑧グローバルスコープとスクリプトスコープの両変数の挙動は変わらない?
 まさかねぇ…今は分からないですが、分かったらエントリー書きます。
---

①を知っておけば、その応用で他項目も類推可能かなぁ、と。。。
それと、変数はデフォルトスコープで使っていくのが良さそうです。

それにしてもすごいです。いろいろできそうですね、これ。
しかし、チームで実装する場合など、どこまで機能を使ってもいいかなど、
コーディング規約等で縛らないと収拾が付かなくなる気がします。

参考サイト:
PowerShell Blog : Controlling the Scope of Variables
++C++;// 未確認飛行 C : 変数

参考コマンド:
Get-Help about_Scopes
Get-Help Set-Variable -Full

修正履歴:

---
以下、上記「言えそうなこと」の根拠となる実行結果データの一部になります。
ここでは、yyyyyy:およびzzzzzz:はデフォルト(何も指定しない)とした場合の
例のみの掲載とします。
デフォルト
0:[global][script][local][private][none]
0:[][][][][]
1:[][][][][]
2:[][][a][a][a]
3:[][][][][a]
3:[][][b][b][b]
4:[][][][][b]
4:[][][c][c][c]
3:[][][b][b][b]
2:[][][a][a][a]
1:[][][][][]
0:[][][][][]

local:
0:[global][script][local][private][none]
0:[][][][][]
1:[][][][][]
2:[][][a][a][a]
3:[][][][][a]
3:[][][b][b][b]
4:[][][][][b]
4:[][][c][c][c]
3:[][][b][b][b]
2:[][][a][a][a]
1:[][][][][]
0:[][][][][]

private:
0:[global][script][local][private][none]
0:[][][][][]
1:[][][][][]
2:[][][a][a][a]
3:[][][][][]
3:[][][][][]
4:[][][][][]
4:[][][][][]
3:[][][][][]
2:[][][a][a][a]
1:[][][][][]
0:[][][][][]

script:
0:[global][script][local][private][none]
0:[][][][][]
1:[][][][][]
2:[a][a][][][a]
3:[a][a][][][a]
3:[a][a][b][b][b]
4:[a][a][][][b]
4:[a][a][c][c][c]
3:[a][a][b][b][b]
2:[a][a][][][a]
1:[a][a][][][a]
0:[a][a][a][a][a]

global:
0:[global][script][local][private][none]
0:[][][][][]
1:[][][][][]
2:[a][a][][][a]
3:[a][a][][][a]
3:[a][a][b][b][b]
4:[a][a][][][b]
4:[a][a][c][c][c]
3:[a][a][b][b][b]
2:[a][a][][][a]
1:[a][a][][][a]
0:[a][a][a][a][a]

0 件のコメント: