【问题标题】:Use proc from inside another proc on TCL在 TCL 上的另一个 proc 内部使用 proc
【发布时间】:2020-12-06 06:32:38
【问题描述】:

我正在尝试在 tcl 中编写一个脚本来对 VMD 执行一些分析。首先我在一个过程中创建一个原子选择,然后我尝试在另一个过程中使用它。

VMD 的原子选择是作为 Tcl 函数实现的。从atomselect 返回的数据是要使用的函数的名称。你可以阅读更多here

当我在proc 之外创建原子选择时,我可以在其中使用它,只需将它作为global 传递。但是现在我在其中创建它,当我尝试使用它时,它只是一个带有过程名称的字符串。

正在恢复,

这行得通:

set all [atomselect top all]

proc test {} {
    global all
    $all num
}

test # Outuputs 7111

但这不是:

proc create {} {
    global all
    set all [atomselect top all]
}

proc test {} {
    global all
    $all num
}

create
test # Outputs -> invalid command name "atomselect1"

【问题讨论】:

  • 我认为如果您将 $all num 放在与 atomselect 相同的过程中它会起作用?这意味着我们正在谈论具有范围绑定的真正恶作剧,这非常不寻常,因为它会导致这样的意外。
  • @DonalFellows 是的,它在create 过程中工作。
  • 谢谢;这足以让我说出发生了什么。

标签: tcl vmd


【解决方案1】:

问题是由atomselect 命令创建的命令在过程返回时被删除。我强烈怀疑这是使用局部变量删除跟踪(在某些未使用的变量上)完成的。当atomselect 在全局范围内运行时,没有这样的自然删除事件(除非全局命名空间被删除,这是一个解释器结束事件),因此永远不会调用跟踪,并且创建的命令会无限期地持续存在。

如果我们像这样重写您的创建:

proc create {} {
    global all
    # Double quotes just because of the highlighting here
    set all [uplevel "#0" atomselect top all]
}

然后atomselect 在全局范围内运行(并且创建的命令应该持续存在),但您的所有其余代码都在您的过程中。

更正确的做法应该是这样:

proc create {} {
    global all
    # Double quotes just because of the highlighting here
    set all [uplevel "#0" [list atomselect top all]]
    # Or this, to better show that we're talking about running a command:
    #   set all [uplevel "#0" [list \
    #       atomselect top all]]
}

当您传递带有空格(或其他元语法字符)的参数时,这一点变得更加重要,因为list 不仅可以生成列表,还可以生成无替换命令。 (事实上​​,构建命令和命令片段绝对是list 命令的主要用途之一;普通数据存储和操作的实际列表往往是使用其他命令。)

【讨论】:

  • atomselect 使用的自动删除技巧的优点是它意味着临时命令会自动删除。如果应用程序通常会生成很多这样的命令,那么对于遵循预期模式的应用程序来说,这可能是一个很好的内存节省。但你没有那样做……
  • 是的,它解决了问题,感谢您的回答和教训。我真的很困惑如何在此上使用 upvar。
  • 使用list 的另一个好处:它在 Tcl 代码中使用了更快的路径。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
相关资源
最近更新 更多