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

当我寻找使用相同变量名的脚本时,如何保护变量。也就是说,即使在脚本中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
# 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
    内(即过程范围外)写入变量时,使用以下优先级顺序:

  • 写入当前命名空间中的现有名称
  • 写入全局命名空间中的现有名称
  • 在当前命名空间中创建一个变量并写入该变量
  • (名称可以通过具有值或出现在
    变量中而存在