Я пытаюсь создать некоторые переменные только для чтения, чтобы использовать их с оцениваемым кодом
Шелте и Донал уже предоставили своевременную и подробную обратную связь. Так что то, что приходит, подразумевается как скромное дополнение. Теперь, когда известно, что следы переменных выполняются после факта , ниже показано, как я имитирую режим только для чтения (или, скорее, keep-re_setting-to-a-one-time-value ) переменных, использующих трассировки (примечание: как объясняет Донал, это не распространяется на переменные pro c -local).
Приведенная ниже реализация допускает следующее:
namespace eval ::ns2 {}
namespace eval ::ns1 {
readOnly foo 1
readOnly ::ns2::bar 2
readOnly ::faz 3
}
На основе variable
, но только для одной пары переменная-значение.
proc ::readOnly {var val} {
uplevel [list variable $var $val]
if {![string match "::*" $var]} {
set var [uplevel [list namespace which -variable $var]]
}
# only proceed iff namespace is not under deletion!
if {[namespace exists [namespace qualifiers $var]]} {
set readOnlyHandler {{var val _ _ op} {
if {[namespace exists [namespace qualifiers $var]]} {
if {$op eq "unset"} {
::readOnly $var $val
} else {
set $var $val
}
# optional: use stderr as err-signalling channel?
puts stderr [list $var is read-only]
}
}}
set handlerScript [list apply $readOnlyHandler $var $val]
set traces [trace info variable $var]
set varTrace [list {write unset} $handlerScript]
if {![llength $traces] || $varTrace ni $traces} {
trace add variable $var {*}$varTrace
}
}
}
Некоторые примечания:
Это предназначено для работы только для глобальных или других переменных с пространством имен, а не для pro c -local;
Он оборачивается вокруг variable
;
[namespace exists ...]
: эти средства защиты защищают от операций, когда заданное родительское пространство имен в настоящее время удаляется (namespace delete ::ns1
или дочернее удаление интерполяции);
В случае unset
сценарий обработчика повторно добавляет трассировку для хорошо воссозданной переменной (в противном случае любая последующая запись больше не будет перехвачена.);
[trace info variable ...]
: помогает избежать добавления избыточных трассировок;
[namespace which -variable]
: обеспечивает работу с полным именем переменной;
Несколько заключительных замечаний:
Ооо, может быть, я смогу заменить обычное отключенное значение на настраиваемую версию и выполнить в нем проверку вместо того, чтобы полагаться на трассировку
Конечно один вариант, но он не дает вам возможности охватить различные (косвенные) пути сброса переменной.
[...] в безопасном интерполяции.
Вы можете захотеть interp alias
между variable
в вашем безопасном интерпре и выше readOnly
в родительском интерпре?