我正在尝试在tcl中编写脚本以对VMD执行一些分析。首先,我在一个过程中创建一个atom选择,然后尝试在另一个过程中使用它。
从VMD中选择原子是作为Tcl函数实现的。从中返回的数据atomselect
是要使用的函数的名称。你可以在这里阅读更多内容。
当我在外部创建原子选择时,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"
问题在于,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代码中使用了更快的路径。