当我使用相同的变量名来源脚本时,如何保护变量。也就是说,即使在脚本中更改了x值,如何在源代码中保留x值。
示例
以下是采购script.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的值(我不想更改名称)。
答案 0 :(得分:3)
一般情况下,如果您有一个脚本来源另一个脚本,而另一个脚本表现不佳(表现良好会让脚本在命名空间中执行所有操作并且通常都很小心),那么您最好赌注是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
以及触及文件系统的所有其他内容)被删除,因此脚本可以用来欺骗你。在这种情况下,它们可能有点过分。
答案 1 :(得分:0)
要证明问题:
% set list {1 2 3 4 5}
1 2 3 4 5
% set x 1
1
% source script.tcl
% set x
5
您可以在proc中获取脚本以引入新的变量范围
% 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
答案 2 :(得分:0)
使用apply
在专用环境中评估源脚本,而不会“污染”采购环境:
apply [list {list} [list source $script.tcl]] $list
那就是说,如果有的话,一个脚本中的数据或状态应该如何传达给另一个脚本并不完全清楚?使用apply
,必须依赖source $script.tcl
的返回值或apply
lambda脚本中的某些范围变量(例如,隐式地通过global
或明确地通过完全限定的变量名称:set ::x 1
)。
答案 3 :(得分:0)
为了完整性:命名空间也可用于包含源操作并控制它访问的变量。
namespace eval TEMP {variable x}
# ... stuff ...
namespace eval TEMP {source script.tcl}
可以使用单个namespace eval
调用,也可以根据需要单独调用。
有一些细微之处。当写入namespace eval
内的变量(在过程范围之外)时,使用以下优先级顺序:
(名称可以通过拥有值或出现在variable
命令调用中来存在。)
读取变量的顺序是
这意味着你可以"泄漏"通过避免使用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
。