2009-02-27 4 views
1

저는 TCL을 처음 사용하고 다른 사람들이 개발 한 일부 코드에 대해 품질 보증을 제공합니다 (실제로는 그렇지 않습니다!). 이 특정 프로그램에는 많은 전역 변수가 있습니다. 때때로 전 세계와 관련하여 종종 upvar가 사용되는 것을 봅니다. 나는 upvar가 pass-by-reference를 모방한다는 것을 이해한다. 그러나 실제적인 차이점은 다음 두 procs 사이에 무엇이 될 것인가?tcl의 upvar와 global 명령의 실제 차이점은 무엇입니까

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이 더 깨끗하게 보일 것 같습니다. 내가 여기서 뭔가를 놓치고 있니?

+0

첫 번째 줄에, 당신은 또한 맞춤법이 틀린 'myBigFatGlobalVariable'3. '안녕하세요'설정하는 3 변수를 'myBigFatGlobalVariable'로 설정하지 않을 유의하십시오. 을 $ 그것이 접두사 변수를 역 참조. 그것은 도움이 그쪽으로 코드를 게시하면 작동합니다. –

답변

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 

큰 차이점은 이것이다 : myFirstProc가 지역 "안녕하세요"는 글로벌이 "안녕하세요", mySecondProc이 설정 설정합니다.

mySecondProc는 "hello"값을 가져 오기 위해 전역 myBigFat ...를 참조하지만 "hello"변수의 범위는 변경하지 않습니다.

myFirstProc는 "hello"값을 매개 변수로받은 다음 스택의 한 프레임 위로 "hello"라는 변수와 로컬 변수 "local"사이에 링크를 만듭니다. "local"을 설정하면 한 프레임을 "hello"스택 위로 설정하는 효과가 있습니다.

은 참조하십시오 :


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

당신이 정말로 "안녕하세요"mySecondProc에서 전역, 당신은 당신이 말하는 global $myBigFatGlobalVariable

+0

고마워, 글렌. 이것은 정확하게 내가 찾고 있었던 설명이었다! –

1

차이점은 upvar 1 $ var local은 위의 레벨에서 $ var에 명명 된 변수에서 local이 값을 취하게합니다. 따라서 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은 글로벌과 동일한 작업을 수행합니다.

+0

감사! 그 대답은이 경우 두 프로가 같은 레벨에서 호출되기 때문에 실제 차이가 없다고 생각합니다. mySecondProc이 myFirstProc를 호출하면 차이점을 알 수 있습니다. –

4

그들은 비슷하지만 약간 다릅니다.

upvar를 사용하면 호출 스택에서 x 단계 위로 변수에 액세스 할 수 있습니다. 반드시 전역 변수 일 필요는 없습니다.

upvar를 사용하여 upvar # 0을 전달하여 전역을 에뮬레이션 할 수 있습니다. varName localVarName 이 경우 로컬 이름으로 전역 변수를 가져옵니다.

참조로 패스를 에뮬레이션하려면 변수의 이름을 전달한 다음 해당 이름에 대해 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는 호출 스택에서 변수에서 얻을 수있는 단지 방법입니다 반환합니다. (global function) 스택을 포함한 함수 (호출 함수)를 호출합니다. 당신이 발동 사이

0

를 추가해야합니다 설정하려면 :

많이 있습니다 이 특정 프로그램에 속한 많은 변수들 ( )

내 experienc e에서 아주 큰 Tcl 응용 프로그램 (20k + 회선)을 사용하면 네임 스페이스를 사용하면 대용량의 전역 변수 내에서 구조를 가져 오는 데 큰 도움이됩니다.

멋진 부분은 코드에 새 모듈을 만들 때마다 반복적으로 추가하거나 코드 일부를 리팩터링하는 것입니다.

namespace eval module1 { 
    variable counter 
    variable name 
} 

namespace eval module2 { 
    variable n 
    variable names 
} 

당신은 모듈 1을 통해 그들에게 참조 할 수 있습니다 : 당신이 :: 카운터

wiki namespace page와 네임 스페이스에 대한 자세한 내용은 Tcl manual page on namespaces를 참조로 전역 변수를 참조 할 수 있습니다대로 카운터 (.

관련 문제