重载标准Tcl命令

mad*_*dia 1 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
Run Code Online (Sandbox Code Playgroud)

Don*_*ows 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
}
Run Code Online (Sandbox Code Playgroud)

在可能的情况下,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
Run Code Online (Sandbox Code Playgroud)

只要你没有太多的代码来讨论谁拥有实际的原始命令,这种技术就可以正常工作.多年来,它已被许多Tcl脚本使用.

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

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

proc runningLappend {cmdAndArgs operation} {
    puts [lrange $cmdAndArgs 1 end]
}
trace add execution lappend enter runningLappend
Run Code Online (Sandbox Code Playgroud)