1

私は TCL の初心者で、他の人が開発したコードの QA を提供しています (実際にはありません!)。この特定のプログラムには非常に多くのグローバル変数があり、upvar が使用されているのを時々見かけます。多くの場合、global と組み合わせて使用​​されます。upvar が参照渡しをエミュレートすることは理解していますが、次の 2 つのプロシージャの実際の違いは何でしょうか?

set myBigFatGloblVariable "hello"

proc myFirstProc { var1 var2 } {
    upvar 1 $var1 local
    set local [expr $var2 * 3]
}

proc mySecondProc { var2 } {
    global myBigFatGlobalVariable
    set $myBigFatGlobalVariable [expr $var2 * 3]
} 

myFirstProc $myBigFatGlobalVariable 3
mySecondProc 3

myFirstProc はよりクリーンで . ここで何か不足していますか?

4

4 に答える 4

4

それらは似ていますが、微妙に異なります。

upvar を使用すると、コール スタックの x レベルまでの変数にアクセスできます。必ずしもグローバル変数である必要はありません。

upvar #0 varName localVarName を渡すことで、upvar を使用してグローバルをエミュレートできます。その場合、ローカル名を持つグローバル変数を取得します。

参照渡しをエミュレートするには、変数の名前を渡し、その名前で upvar を呼び出します。

変数の名前がわかっている場合は、そのまま使用できます。

次のコードを確認してください。

    # here there is only 1 global variable, but we also need to access to variables defined in the calling functions
    proc p3 {} {
        # upvar defaults to 1, so not needed to put in here
        # also notice you can call upvar on more than one variable
        upvar dog myDog horse myHorse cat myCat
        upvar 2 cow myCow alpha myAlpha
        upvar #0 samurai mySamurai
        puts "Level 1: $myDog $myHorse $myCat"
        puts "Level 2: $myCow $myAlpha"
        puts "Global : $mySamurai"
    }
    proc p2 {} {
        set dog "bowow"
        set horse "niegh"
        set cat "meow"
        p3

    }
    proc p1 {} {
        set cow "moo"
        set alpha "beta"
        p2
    }

    set samurai "japan"
    p1

これは戻ります

    Level 1: bowow niegh meow
    Level 2: moo beta
    Global : japan

upvar は、コール スタックから変数を取得する方法にすぎません。(呼び出し関数) 'グローバル' スタックを含みます。

于 2009-02-27T20:49:06.003 に答える
2
set myBigFatGlobalVariable "hello"

proc myFirstProc { var1 var2 } {
    upvar 1 $var1 local
    set local [expr $var2 * 3] }

proc mySecondProc { var2 } {
    global myBigFatGlobalVariable
    set $myBigFatGlobalVariable [expr $var2 * 3] } 

myFirstProc $myBigFatGlobalVariable 3
mySecondProc 3

2 つの proc の大きな違いは次のとおりです。myFirstProc はグローバルな「hello」を設定し、mySecondProc はローカルの「hello」を設定します。

mySecondProc はグローバル myBigFat... を参照して値「hello」を取得しますが、「hello」変数のスコープは変更しません。

myFirstProc は値「hello」をパラメーターとして受け取り、スタックの 1 フレーム上の「hello」という名前の変数とローカル変数「local」との間のリンクを作成します。「local」を設定すると、スタックの 1 フレーム上に「hello」を設定する効果があります。

見る:


myFirstProc $myBigFatGlobalVariable 3
puts $hello ;# ==> 9
unset hello
mySecondProc 3
puts $hello ;# ==> can't read "hello": no such variable

mySecondProc からグローバルな "hello" を本当に設定したい場合は、追加する必要がありますglobal $myBigFatGlobalVariable

于 2009-03-09T11:30:10.007 に答える
1

違いは、upv​​ar 1 $var local が local に、上のレベルの $var で指定された変数から値を取得させることです。したがって、myBigFatGlobalVariable では $var をグローバル スコープで定義する必要はありません。

proc p1 { var1 } {
upvar 1 $var1 local1
puts $local1
}

proc p2 { } {
set local2 "local2"
p1 local2
}

set global1 "global1"
p1 global1
p2

p1 は、コール スタックの 1 つ上のレベルから var1 の値を出力します。グローバルは常に最上位で定義されるため、upvar #0 はグローバルと同じことを行います。

于 2009-02-27T20:36:38.137 に答える
0

あなたが言っています:

この特定のプログラムには、非常に多くのグローバル変数があります

中規模から非常に大規模な Tcl アプリケーション (2 万行以上!) での私の経験では、名前空間を使用すると、大量のグローバル変数内で構造を取得するのに非常に役立ちます。

良い点は、新しいモジュールをコードに作成するたびに繰り返し追加したり、コードの一部をリファクタリングしたりできることです。

namespace eval module1 {
  variable counter
  variable name
}

namespace eval module2 {
  variable n
  variable names
}

module1::counter を介してそれらを参照できます (グローバル変数を ::counter として参照できるように)

名前空間の詳細については、名前空間に関するwiki 名前空間ページTcl マニュアル ページを参照してください

于 2009-03-11T06:49:52.503 に答える