каковы практические различия между упваром и глобальными командами в tcl - PullRequest
1 голос
/ 27 февраля 2009

Я довольно новичок в TCL и предоставляю QA для некоторого кода, разработанного другими (на самом деле нет!). В этой конкретной программе много и много глобальных переменных, и я иногда вижу, что используется 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 будет чище и. Я что-то здесь упускаю?

Ответы [ 4 ]

4 голосов
/ 27 февраля 2009

Они похожи, но немного отличаются.

upvar позволяет вам получить доступ к переменным до уровня x в стеке вызовов. Они не обязательно должны быть глобальными переменными.

Вы можете использовать upvar для эмуляции global, передавая 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 - это просто способ получить переменные из стека вызовов. (вызов функций), включая «глобальный» стек.

2 голосов
/ 09 марта 2009
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 устанавливает global"привет", mySecondProc устанавливает local"привет".

mySecondProc ссылается на глобальный myBigFat ..., чтобы получить значение "привет", но не изменяет область действия переменной "привет".

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

1 голос
/ 27 февраля 2009

Разница в том, что upvar 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 выведет значение var1 с уровня 1 над ним в стеке вызовов. Глобальный всегда определяется на верхнем уровне, поэтому upvar # 0 делает то же самое, что глобальный.

0 голосов
/ 11 марта 2009

Вы говорите:

Есть много и много глобальных переменные в этой конкретной программе

Мой опыт работы со средними и очень большими Tcl-приложениями (20k + строк!) Заключается в том, что использование пространств имен значительно поможет получить структуру в большом количестве глобальных переменных.

Приятной особенностью является то, что вы можете добавлять их итеративно каждый раз, когда создаете новый модуль в коде, или путем рефакторинга некоторого кода.

namespace eval module1 {
  variable counter
  variable name
}

namespace eval module2 {
  variable n
  variable names
}

Вы можете ссылаться на них через module1 :: counter (так же, как вы можете ссылаться на глобальную переменную как :: counter

См. Страницу вики-пространства имен и справочную страницу Tcl по пространствам имен для получения дополнительной информации о пространствах имен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...