2

Upvar は、コール スタックと呼ばれることもある別のスタック フレーム、または 別のスコープ内の変数へのリンクを作成します。

Upvar は、グローバル (または名前空間) 変数のエイリアスを作成するためにも使用されます2ただし、名前空間は、 namespace evalコマンドによってのみ作成されます。proc コマンドによって、新しいスタック フレームが作成されます。

ネームスペースとコール スタックは、TCL ネーミング コンテキストを変更できる 2 つの方法のようです。Upvar と Uplevel は、名前空間とコール スタックの両方で機能します。

私はそれを正しく理解しましたか?コール スタックと名前空間の直接的な比較はまだ見ていないので、質問します。

4

1 に答える 1

8

いいえ、そうではありません。名前空間と呼び出しフレームは、まったく異なる概念です。名前空間は、シノニムを明確にすることができる名前の階層構造です。プログラムで3 つの変数に名前fooを付ける場合がありますが、それらを異なる名前空間に配置しても衝突しません。名前空間は、変数名とコマンド名の両方に使用できます。名前空間の内容で作成されるとnamespace eval、それを呼び出すまで常にアクセスできますnamespace delete

コール スタックは、一連のスタック フレームです。最初のスタック フレーム #0 は常に存在します。コマンドが呼び出されるたびに、他のスタック フレームが作成されます (これは主に、ユーザー定義の手順であるコマンドに当てはまります。「組み込み」コマンドは独自の規則に従います)。コマンドが戻ると、それらは再び破棄されます。したがって、コマンド A を呼び出し、A がコマンド B を呼び出し、B がコマンド C を呼び出すと、コール スタックは次のようになります。

#3 : <C's variables>
#2 : <B's variables>
#1 : <A's variables>
#0 : <global and namespace variables>

を使用しない限り、各スタック フレームは、そこで作成された変数またはそこにインポートされた変数のみにアクセスできるという意味でスコープですupvar。他のすべては隠されています。ほとんどのプログラミング言語では、グローバル スコープなどの外部スコープからの名前は、内部スコープから自動的にアクセスできます。Tcl ではそうではありません。

you を使用upvarすると、コマンドが独自のスタック フレームの外にあるものを見ることができます。たとえば、C は を使用upvar #0 foo barbarてグローバル変数のエイリアス ( ) を作成したり、B のスタック フレーム内の変数のエイリアス ( ) を作成するために (# なしで注意) をfoo使用したりできます。upvar 1 baz quxquxbaz

このuplevelコマンドを同じ行で使用して、グローバル スタックを含む別のスタック フレームでスクリプトを実行できます。実行中、スクリプトはそのスタック フレーム内のすべてのものにアクセスできますが、uplevel呼び出し元のスタック フレーム内の変数を含め、それ以外にはアクセスできません。

::abc::defC はを使用して名前空間変数のエイリアスを作成することもできますupvar #0 ::abc::def ghiが、それを行わず、namespace upvar ::abc def ghi代わりに使用してください。

代わりに、グローバル変数をインポートするためにupvar #0 foo foo使用できます。global foo名前空間で定義されたコマンド内で、コマンドvariableは同じ名前空間で定義された変数をインポートできます。

これは、#0 (グローバル フレーム) または 1 (呼び出し元のフレーム) へまたは #0 への挿入にupvar役立つことがよくあります。uplevel他のフレーム番号を使用するとエラーが発生しやすくなり、通常は設計が不十分であることを示しています。この呼び出しにより、同じスタック フレーム内に変数 ( )upvar 0 foo barのエイリアス ( ) が作成されます。これは驚くほど便利です。barfoo

処理中のイベントによって呼び出されるコマンドは、グローバル レベルを使用してコール スタックの外部で実行されます。それらがアクティブなスタック フレーム内に到達し、そこに存在する変数にアクセスする方法はありません。

簡単なデモンストレーション:

namespace eval ::abc {
    variable def 42

    proc xyz {} {
        variable def
    }
}

set foo 1138

proc A {} {
    B
}

proc B {} {
    set baz 1337
    C
}

proc C {} {
    upvar #0 foo bar
    puts $bar
    upvar 1 baz qux
    puts $qux
    namespace upvar ::abc def ghi
    puts $ghi
}
于 2015-01-15T19:04:54.550 に答える