2015-01-15 3 views
2

Upvar создает ссылку на переменную в different stack frame, иногда называемую call stack, или different scope.В чем разница между пространством имен TCL и фреймом стека?

Upvar также используется для создания псевдонима для глобальной (или пространства имен) переменной 2. Но пространство имен создается только командой namespace eval. Команда proc создает новый стек стека.

Пространство имен и стеки вызовов выглядят как два способа изменения TCL naming context. Upvar и Uplevel могут работать как в пространствах имен, так и в столах вызовов.

Правильно ли я понял? Мне еще предстоит увидеть прямое сравнение стеков вызовов и пространств имен, поэтому мой вопрос.

ответ

8

Нет, не совсем. Пространства имен и фреймы вызовов - это очень разные понятия. Пространство имен - это иерархическая структура имен, которая может устранить синонимы. В вашей программе могут быть три переменные с именем foo, но они не будут сталкиваться, если вы поместите их в разные пространства имен. Пространства имен могут использоваться как для имен переменных, так и для команд. После создания с namespace eval содержимое пространства имен всегда доступно, пока вы не назовете на нем namespace delete.

Стек вызовов представляет собой последовательность кадров стека. Первый стек кадров # 0 всегда существует. Другие кадры стека создаются всякий раз, когда вызывается команда (это в основном используется для команд, которые являются определяемыми пользователем процедурами, «встроенные» команды следуют своим собственным правилам). Они снова уничтожаются, когда команда возвращается. Так что, если вы вызовите команду A, и А вызывает команду B и B вызывает команду C, то есть стек вызовов, который выглядит следующим образом:

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

Каждый кадр стека является сферой в том смысле, что только переменные, создаются там или импортируются в него, могут быть доступны, если вы не используете upvar. Все остальное скрыто. В большинстве языков программирования имена из внешней области, такие как глобальная область, могут быть автоматически доступны из внутренней области. Не так в Tcl.

Используя команду upvar, вы можете позволить команде посмотреть на вещи вне своей собственной стековой рамки. C может, например, использовать upvar #0 foo bar для создания псевдонима (bar) для глобальной переменной foo или использовать upvar 1 baz qux (отметить без #), чтобы создать псевдоним (qux) для переменной baz в кадре стека B.

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

C также может создать псевдоним для переменной пространства имен ::abc::def, используя upvar #0 ::abc::def ghi, но не делайте этого, вместо этого используйте namespace upvar ::abc def ghi.

Вместо upvar #0 foo foo вы можете использовать global foo, чтобы импортировать глобальную переменную. Внутри команды, определенной в пространстве имен, команда variable может импортировать переменные, определенные в том же пространстве имен.

Часто полезно использовать upvar или uplevel в # 0 (глобальный фрейм) или 1 (рамка звонящего). Использование других номеров кадров является подверженным ошибкам и обычно указывает на плохой дизайн.Вызов upvar 0 foo bar создает псевдоним (bar) для переменной (foo) в том же стеке стека, что может быть неожиданно полезно.

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

Простая демонстрация:

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 
} 
+0

только некоторые команды нажмите кадры стека. Те, о которых все знают, - это вызовы процедур и 'namespace eval'. (Есть несколько других, особенно в TclOO ...) –

+0

Спасибо, @Hoodiecrow, вы заполнили некоторые детали. Многие поисковые запросы показали мне, что пространства имен отличаются от кадров вызовов. И это пространство имен является необязательным и, пожалуй, лучше всего избегать в небольших скриптах (но полезно для повторного использования кода). Кроме того, кадры вызова создаются всякий раз, когда вызывается процедура. Чтобы прояснить далее: Я сформулировал в моем вопросе что-то неверное? –

+1

@ user901750: есть некоторые проблемные утверждения. Вы говорите, что стек стека иногда называют стеком вызовов. Это неправильно, но я полагаю, что это была ошибка? Команда 'proc' не создает фреймы стека (но команды, которые она создает, при вызове). Пространство имен не изменяет контекст именования Tcl, но 'namespace eval' делает (путем создания нового фрейма стека). 'upvar' и' uplevel' не работают (манипулируют) пространствами имен как таковые, но могут обращаться к переменным пространства имен так же, как любая другая команда, которая обрабатывает переменные. –

Смежные вопросы