重命名命名空间导致 TCL 出现问题

Renaming puts in namespace causes issue in TCL

当我尝试重命名 name-space 中的 puts 命令时,它导致了问题。我重命名 puts 是因为我不想显示特定过程的 echo 语句。

namespace eval temp {
    namespace export print_proc
    proc replacement_puts args {}
    proc silentEval {script} {
        rename puts original_puts
        interp alias {} puts {} temp::replacement_puts
        catch [list uplevel 1 $script] msg opts
        rename puts {}
        rename original_puts puts
        return -options $opts $msg
    }
    proc print_proc {} {
        puts "before call"
        silentEval {a}
        puts "aftter call"
    }
    proc a {} {
        puts "inner call"
    }
}

package provide temp 1.0

在例子中,我不想显示proc a的echo语句。

但是执行后,报错Invalid Command Name "puts"

谢谢

您只需明确说明您正在更改全局 puts

namespace eval temp {
    proc silentEval {script} {
        rename ::puts ::original_puts
        proc ::puts args {}
        catch [list uplevel 1 $script] msg opts
        rename ::puts {}
        rename ::original_puts ::puts
        return -options $opts $msg
    }
}

Glenn Jackman 的回答应该可以解决您的问题。我只想指出,您实际上不需要重命名任何内容。使用此定义:

namespace eval temp {
    namespace export print_proc
    proc puts args {}
    proc silentEval script {
        catch [list uplevel 1 $script] msg opts
        return -options $opts $msg
    }
    proc print_proc {} {
        ::puts "before call"
        silentEval a
        ::puts "aftter call"
    }
    proc a {} {
        puts "inner call"
    }
}

当调用 a 并调用 puts 时,它实际上会调用 ::temp::puts 命令而不是全局 puts -- 实际上,命名空间puts 覆盖全局 puts。在 print_proc 中,我们希望调用全局 puts,因此我们在名称前添加 ::

当然,所有这些都适用于在 ::temp 中定义的脚本,就像示例中那样。

(如果您只是要 re-throw 异常,那么调用 catch 没有多大意义,但我想这只是占位符代码。)

文档:catch, list, namespace, proc, puts, return