重载标准的Tcl命令

3

与过程相关的小查询范围

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

@ShiDoiSi:我猜“它不起作用;为什么?帮帮我!”大概就涵盖了吧。 - Donal Fellows
1个回答

14

如果你只是这样做,它不会起作用。它会替换标准的 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脚本都在使用它。

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

当然,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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接