В чем разница между пространством имен TCL и фреймом стека?

Upvar создает ссылку на переменную в другом кадре стека, иногда называемом стеком вызовов, или в другой области видимости.

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

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

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

1 ответ

Нет не совсем Пространства имен и фреймы вызовов - это очень разные понятия. Пространство имен - это иерархическая структура имен, которая может устранить неоднозначность синонимов. У вас может быть три переменные 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.

С помощью 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
}
Другие вопросы по тегам