Tcl 如何保护变量不被覆盖
当我寻找使用相同变量名的脚本时,如何保护变量。也就是说,即使在脚本中x值发生了更改,我如何在源代码返回的值中保留x值 示例 下面是sourcing script.tcl的主要代码:Tcl 如何保护变量不被覆盖,tcl,Tcl,当我寻找使用相同变量名的脚本时,如何保护变量。也就是说,即使在脚本中x值发生了更改,我如何在源代码返回的值中保留x值 示例 下面是sourcing script.tcl的主要代码: set list {1 2 3 4 5} set x 1 source $script.tcl # some script with loop on x: foreach x $list {} script.tcl: set list {1 2 3 4 5} set x 1 source $script.tcl
set list {1 2 3 4 5}
set x 1
source $script.tcl
# some script with loop on x:
foreach x $list {}
script.tcl:
set list {1 2 3 4 5}
set x 1
source $script.tcl
# some script with loop on x:
foreach x $list {}
问题是x等于文件源之前的某个值(在本例中为“1”),但在源操作之后,x是列表中的最后一个迭代值
我想保留x的值(我不想更改名称)。要演示此问题:
% 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
要演示问题,请执行以下操作:
% 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
使用
apply
在专用环境中评估源脚本,而不会“污染”源上下文:
apply [list {list} [list source $script.tcl]] $list
也就是说,还不完全清楚一个脚本中的数据或状态应该如何传递给另一个脚本(如果有的话)?使用
apply
,必须依赖source$script.tcl
的返回值或apply
lambda脚本中的一些作用域变量(例如,隐式地通过global
或显式地通过完全限定的变量名:set::x 1
).使用apply
在专用环境中评估源脚本,而不会“污染”源上下文:
apply [list {list} [list source $script.tcl]] $list
也就是说,还不完全清楚一个脚本中的数据或状态应该如何传递给另一个脚本(如果有的话)?使用
apply
,必须依赖source$script.tcl
的返回值或apply
lambda脚本中的一些作用域变量(例如,隐式地通过global
或显式地通过完全限定的变量名:set::x1
),如果您有一个脚本在另一个脚本表现不好的情况下寻找另一个脚本(表现良好需要脚本在名称空间中执行所有操作,并且通常要小心),那么最好的办法是在子解释器中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
和所有其他与文件系统相关的命令)的子解释器,这样脚本就不会愚弄您了。在这种情况下,它们可能有些过分。一般来说,如果您有一个脚本在另一个脚本表现不好的情况下寻找另一个脚本(表现良好需要脚本在名称空间中执行所有操作,并且通常要小心),那么最好的办法是在子解释器中源代码
# 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
和所有其他与文件系统相关的命令)的子解释器,这样脚本就不会愚弄您了。在这个实例中,它们可能有些过分。为了完整性:名称空间还可以用来包含源操作并控制它访问哪些变量
namespace eval TEMP {variable x}
# ... stuff ...
namespace eval TEMP {source script.tcl}
可以使用单个命名空间eval
调用,也可以根据需要单独调用
有一些微妙之处。在命名空间eval
内(即过程范围外)写入变量时,使用以下优先级顺序:
写入当前命名空间中的现有名称
写入全局命名空间中的现有名称
在当前命名空间中创建一个变量并写入该变量
(名称可以通过具有值或出现在变量命令调用中而存在。)
读取变量的顺序是
从当前命名空间中的现有名称读取(如果没有值,则失败)
从全局命名空间中的现有名称读取(如果没有值,则失败)
失败
这意味着您可以通过避免在全局名称空间中使用variable
,将变量“泄漏”到当前名称空间中。在本例中,列表
变量的值就是这样访问的。通过确保当前名称空间中存在一个现有名称,全局名称将被隐藏并防止读取或写入
通过确保变量有一个全局名称(并再次避免使用variable
),可以类似地“泄漏”变量
例如,如果script.tcl
中的脚本
# some script with loop on x:
foreach x $list {incr n $x}
你是这样做的
set n 0
namespace eval TEMP {source script.tcl}
然后
没有集合n0
,名称n
被创建为::TEMP::n
只是为了完整性:命名空间还可以用来包含源操作并控制它访问的变量
namespace eval TEMP {variable x}
# ... stuff ...
namespace eval TEMP {source script.tcl}
可以使用单个命名空间eval
调用,也可以根据需要单独调用
有一些微妙之处。在命名空间eval
内(即过程范围外)写入变量时,使用以下优先级顺序:
写入当前命名空间中的现有名称
写入全局命名空间中的现有名称
在当前命名空间中创建一个变量并写入该变量
(名称可以通过具有值或出现在变量中而存在