考虑一个如下结构的库:
package provide ::mylib 1.0
namespace eval ::mylib {
namespace export f
proc f { action } {
# pass action around
g $action
}
proc g { action } {
eval $action
}
}
如果我尝试这样使用它,它就不会工作:
....
namespace eval ::user {
set x 10
::mylib::f { puts $x }
}
原因是mylib中不知道$ x。我可以像这样修理它:
namespace eval ::user {
set x 10
::mylib::f { puts $::user::x }
}
这样可行,但是将参数中的每个变量限定为:: mylib :: f都很笨拙。另一种可能性是将代码包装在另一个名称空间eval:
中namespace eval ::user {
set x 10
::mylib::f { namespace eval { puts $x } }
}
更好,但仍然很难看。如果是Ruby或Perl,我只需将一个闭包传递给:: mylib :: f。 Tcl的最佳实践是什么?
顺便说一下,我现在正在使用Tcl 8.3,但希望很快就能升级到更新的版本,因此8.3和更新版本的解决方案很受欢迎。答案 0 :(得分:2)
tl; dr版本:namespace code
namespace code
命令适用于这种情况。您将要封装的脚本传递给它,它会将您带回魔法的版本交给它,以便它可以处理从任何地方调用的内容。以下是您可以使用它的方法。
namespace eval ::user {
variable x 10
::mylib::f [namespace code { puts $x }]
}
在内部,它使用namespace inscope
来执行此操作。建议您不要直接使用它; namespace code
是执行此操作的便捷方式。
请注意,如果回调站点向其传递参数,它甚至可以工作,只要该站点正在执行:
eval $callback [list "the argument is this"]
(事实上,在8.3中,由于eval
中的严重黑客,unknown
不是必需的,但请按我上面建议的方式进行,因为我们采取了在以后的版本中出现问题。这非常糟糕。)