如何保护变量不被覆盖

时间:2018-05-28 13:11:45

标签: tcl

当我使用相同的变量名来源脚本时,如何保护变量。也就是说,即使在脚本中更改了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的值(我不想更改名称)。

4 个答案:

答案 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内的变量(在过程范围之外)时,使用以下优先级顺序:

  1. 写入当前名称空间中的现有名称
  2. 写入全局命名空间中的现有名称
  3. 在当前命名空间中创建一个变量并写入
  4. (名称可以通过拥有值或出现在variable命令调用中来存在。)

    读取变量的顺序是

    1. 从当前命名空间中的现有名称读取(如果没有值则失败)
    2. 从全局命名空间中的现有名称读取(如果没有值则失败)
    3. 失败
    4. 这意味着你可以"泄漏"通过避免使用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