Как защитить переменную от перезаписи - PullRequest
0 голосов
/ 28 мая 2018

Как я могу защитить переменную, когда я использую скрипт, использующий то же имя переменной.То есть, как я могу сохранить значение x в возврате из источника, даже если оно изменилось в сценарии.

пример

Вот основной код этого сценария поиска.tcl:

set list {1 2 3 4 5}
set x 1
source $script.tcl

script.tcl:

# some script with loop on x:
foreach x $list {}

Проблема в том, что x равно некоторому значению (в данном случае «1») перед источником файла, но послеисходная операция, x является последним значением итерации из списка.

Я бы хотел сохранить значение x (и не хочу менять имена).

Ответы [ 4 ]

0 голосов
/ 29 мая 2018

Просто для полноты: пространство имен может также использоваться для хранения исходной операции и контроля того, к каким переменным он обращается.

namespace eval TEMP {variable x}
# ... stuff ...
namespace eval TEMP {source script.tcl}

Можно использовать один вызов namespace eval или, при желании, отдельный вызов.

Есть некоторые тонкости.При записи в переменную внутри namespace eval (то есть вне области действия процедуры) используется следующий порядок приоритетов:

  1. запись в существующее имя в текущем пространстве имен
  2. запись в существующее имя в глобальном пространстве имен
  3. создание переменной в текущем пространстве имен и запись в нее

(Имена могут существовать, имея значение или появляясь вvariable вызов команды.)

Порядок чтения переменной:

  1. чтение из существующего имени в текущем пространстве имен (сбой, если оно не имеет значения)
  2. чтение из существующего имени в глобальном пространстве имен (сбой, если оно не имеет значения)
  3. сбой

Это означает, что вы можете «просочиться» переменные из глобального пространства имен вток на , избегая , используя variable на них.В этом примере доступ к значению переменной list осуществляется таким образом.Убедившись, что в текущем пространстве имен существует существующее имя, глобальное имя будет затенено и защищено от чтения или записи.

Аналогичным образом можно «вытекать» переменные, убедившись, что для них есть глобальное имя(и снова избегая использования variable).

Например, если сценарий в script.tcl равен

# some script with loop on x:
foreach x $list {incr n $x}

, и вы используете его как

set n 0
namespace eval TEMP {source script.tcl}

затем

set n
# => 15

Без set n 0 имя n вместо этого создается как ::TEMP::n.

0 голосов
/ 28 мая 2018

Используйте apply для оценки исходного сценария в выделенной среде, без "загрязнения" контекста источника:

apply [list {list} [list source $script.tcl]] $list

Тем не менее, не совсем ясно, как данные или состояние из одного сценария должныбыть сообщенным другому, если вообще?Используя apply, можно полагаться на возвращаемое значение из source $script.tcl или некоторые переменные из области действия из лямбда-сценария apply (например, неявно через global или явно через полностью определенные имена переменных: set ::x 1).

0 голосов
/ 28 мая 2018

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

# Here is our protected variable
set x "a very important value"

# Make the child
interp create child

# Set it up to be ready
child eval [list set list {1 2 3 4 5}]

# Run the script
catch {
    child eval [list source script.tcl]
}

# Possibly get things from that interpreter here

# Dispose of the interpreter
interp delete child

# Show that the variable is OK
puts $x

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

Для действительно ненадежных других сценариев вы можете использовать безопасный интерпретатор;это дочерние интерпретаторы с удаленными небезопасными командами (включая source и все остальное, что касается файловой системы), так что сценарий может сделать намного меньше, чтобы обмануть вас.Они могут быть излишними в этом случае.

0 голосов
/ 28 мая 2018

Чтобы продемонстрировать проблему:

% set list {1 2 3 4 5}
1 2 3 4 5
% set x 1
1
% source script.tcl
% set x
5

Вы можете написать сценарий в процедуре, чтобы ввести новую переменную scope

% proc do_script {} {
    upvar 1 list list   ;# make $list available in this scope
    source script.tcl
    puts "in proc, x=$x"
}
% set x 1
1
% do_script
in proc, x=5
% set x
1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...