首页 > 解决方案 > 在 TCL 上的另一个 proc 内部使用 proc

问题描述

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

来自 VMD 的原子选择被实现为 Tcl 函数。返回的数据atomselect是要使用的函数的名称。你可以在这里阅读更多。

当我在 a 之外创建原子选择时,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"

标签: tclvmd

解决方案


问题是该命令创建的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;普通数据存储和操作的实际列表往往由其他命令组成。)


推荐阅读