重载标准Tcl命令

时间:2012-01-18 10:02:58

标签: tcl

程序的小查询相关范围

proc lappend {args} {
   set a $args
   lappend a testing ;# want to call the inbuilt tcl lappend command
   puts "$a"
}

set list {new to tcl}
lappend $list

1 个答案:

答案 0 :(得分:12)

如果你这样做,它将无法正常工作。它将替换标准lappend并且您将获得无限递归(好吧,您将进行堆栈深度检查)。有几种方法可以解决这个问题。

将代码放入命名空间

如果您的代码位于命名空间中,它将首先解析该命名空间中的lappend,并且只有在本地搜索失败时才使用全局命名空间。您可以这样使用:

namespace eval myNS {
    proc lappend {args} {
        set a $args
        ::lappend a testing ;# Force the use of the global lappend command
        puts "$a"
    }

    set list {new to tcl}
    lappend $list
}

有可能的变体,namespace eval myNS {source example.tcl}(你的代码在源文件中几乎逐字逐句)是一个更有趣的,因为它允许代码主要是不可知的到命名空间。

重命名全局lappend命令

您也可以将标准命令移开,如下所示:

rename lappend lappend_original
proc lappend {args} {
   set a $args
   lappend_original a testing
   puts "$a"
}

set list {new to tcl}
lappend $list

这项技术工作得很好,只要你没有太多的代码就这个实际的原始命令交战。多年来,许多Tcl脚本都使用它。

Real 问题的解决方案:执行跟踪

当然,lappend命令不是您真正想要替换的命令,因为它在很多Tcl库代码中被大量使用。对于确定一段代码实际调用lappend的位置以及传入了哪些参数的问题,使用execution trace要好得多。 (链接有Tcl 8.6文档,但是这个API自Tcl 8.4以来已经存在,所以你应该可以使用它。)

proc runningLappend {cmdAndArgs operation} {
    puts [lrange $cmdAndArgs 1 end]
}
trace add execution lappend enter runningLappend