将 proc 复制到 TCL 中的命名空间

copying a proc to a namespace in TCL

这是问题的简化案例。我正在尝试将过程复制到名称空间,以便它使用名称空间自己的上下文。使用 import 不起作用(可能是因为它只是创建了别名)参见下面的代码:

proc me_namespace {} {
 puts "namespace is:[namespace current]"
 puts "called namespace is:[uplevel 1 namespace current ]"
}
namespace eval foo {} {
 me_namespace
 puts "Now import"
 namespace import ::::me_namespace
 me_namespace
}

代码输出为:

namespace is:::
called namespace is:::foo
Now import
namespace is:::
called namespace is:::foo
namespace is:::foo

理想情况下,复制后的 proc me_namespace 第一行输出应该是:

::::me_namespace

有什么想法吗?我唯一能想到的是将过程定义放在一个文件中,然后读取该文件并使用 eval,但我一直在寻找更优雅的东西。 我不只使用 uplevel 的原因是有时(特别是当使用 variableuplevel 时,运行时间有时太慢了。TCL 版本是8.6

过程绑定到它们包含的名称空间。重命名过程,更改其绑定。 (我讨厌那样!)要在另一个名称空间中重新创建过程,您实际上必须重命名(移动)或重新运行创建原始过程的 proc

现在,虽然我真的建议您在遇到此类问题时考虑使用 TclOO,但您也许可以使用不同的技术。 namespace upvar 命令相当快,您可以像这样使用它:

proc master_version_of_foo {ns args} {
    namespace upvar $ns abc local1 def local2
    # ... continue with your code in here
}

# Stamp out some copies
namespace eval ::x {}
interp alias {} ::x::foo {} ::master_version_of_foo ::x
namespace eval ::y {}
interp alias {} ::y::foo {} ::master_version_of_foo ::y
namespace eval ::z {}
interp alias {} ::z::foo {} ::master_version_of_foo ::z

这些真正的命令别名非常快,变量绑定也非常快(速度与 global 命令相似;它们在内部使用几乎相同的字节码操作)并且您将共享编译该过程本身非常快。

不这样做的主要原因是如果您在三种情况下需要不同的命令解析。在这一点上,最快的路线都经过 TclOO(它驯服了 Tcl 的许多高级功能以达到可用的程度)并且可能需要您进行一些认真的重新设计才能很好地使用。