2016-09-26 84 views
0
覆盖一个过程的局部变量

所以我有以下情况:如何有效地在TCL

$ ls -l 
-r--r----- 1.tcl 
-rw-rw---- 2.tcl 

$ cat 1.tcl 
proc foo {args} { 
    puts "$bar" 
} 

,我需要做出比其他"can't read \"bar\""打印1.tcl东西。在一个良好的编程语言,明显的解决办法是

$ cat > 2.tcl 
set -global bar "hello, world" 
foo 

什么将是TCL一个合理的解决方法吗?不幸的是,真正的foo是一个长时间的功能,我无法在运行时真正制作临时文件的副本或sed

+0

可以设置具有相同名称的全局变量并链接到它,例如通过在程序主体的开头添加一个'global'调用,就像Glenn所建议的那样。但它不会起作用。在程序代码中的某处,在打印“bar”的值之前,该值将被设置为现在使用的值。链接到全局变量不能防止发生这种变化。 –

+0

如果我看到这个问题,我可能会说同样的事情,但功能实际上已经坏了,我不能修复它。很显然,代码已经从其他地方复制过来,但是这个变量肯定是未定义的。 (或者我误解了你的意思?) – user234461

+0

不,误解是我的。我只是假设没有人会用一个有未定义变量的程序。 –

回答

0
source 1.tcl 

try { 
    foo 
} on error {err res} { 
    set einfo [dict get $res -errorinfo] 
    if { [regexp {no such variable} $einfo] } { 
    puts "hello, world" 
    return -code 0 
    } else { 
    puts $einfo 
    return -code [dict get $res -code] 
    } 
} 
+0

这显然不适用于控制过程中未定义变量值的一般情况。 – user234461

+1

以上评论是针对以前的修改。查看编辑历史记录。 –

1

您可以为您具体的例子

$ cat 2.tcl 
source 1.tcl 
set bar "Hello, bar!" 
# add a "global bar" command to the foo procedure 
proc foo [info args foo] "global bar; [info body foo]" 
foo 

$ tclsh 2.tcl 
Hello, bar! 

显然,这并不规模非常好做

1

如果变量只是不确定的,最简单的方法是用一个定义来修补程序:

proc foo [info args foo] "set bar \"hello, world\" ; [info body foo]" 

您也可以使用读取跟踪和助手命令做到这一点。这消除了我上面提到的问题,其中本地任务会破坏您想要注入的值。

原始程序,带有一个将局部变量设置为稍后打印的值的附加命令。

proc foo args { 
    set bar foobar 
    puts "$bar" 
} 
% foo 
foobar 

创建一个全局变量(名称是否相同并不重要)。

set bar "hello, world" 

创建一个帮助命令获取本地变量的名称,链接到它,并赋予全局变量到它的价值。既然我们已经知道了名字,我们可以在程序中对它进行硬编码,但这更灵活。

proc readbar {name args} { 
    upvar 1 $name var 
    global bar 
    set var $bar 
} 

将跟踪添加到foo过程的主体。只要读取本地变量bar,即会尝试检索其值,就会触发跟踪。跟踪触发时,将调用命令readbar:它将用全局设置值覆盖变量的当前值。

proc foo [info args foo] "trace add variable bar read readbar; [info body foo]" 

% foo 
hello, world 

如果不希望污染与助手命令的命名空间,可以使用,而不是一个匿名函数:

proc foo [info args foo] [format {trace add variable bar read {apply {{name args} { 
    upvar 1 $name var 
    global bar 
    set var $bar 
}}} ; %s} [info body foo]] 

文档: applyformatglobalinfoproc, puts, set, traceupvarSyntax of Tcl regular expressions

+0

请注意,在他的问题“酒吧”没有设置。他不想改变1.tcl。另见他的评论回复我的第一个编辑。我不确定OP的问题是否反映了OP的真正需求。 –

+0

@BradLanam你是对的我并不是真的意味着重写,“从函数外部定义”本来就是一种更好的方式。无论如何,这个答案涵盖两种情况。 – user234461

0

Tcl的过程不能解决变量不是系统默认的局部变量的任何其他。您必须明确地要求他们参考其他内容(例如,使用global,variableupvar)。这意味着一眼就可以看到非本地事物是否正在发生,并且脚本无法工作。

可以用变量解析器覆盖这种行为,但Tcl并没有真正在其脚本接口中公开该API。一些扩展可以做更多。例如,它可能工作使用[incr Tcl](即itcl),因为它为其对象中的变量做这种事情。我不记得Expect是否也会这样做,或者如果使用特殊代码来处理它的变量。

当然,你可能真的偷偷摸摸,并重写proc的行为。

rename proc real_proc 
real_proc proc {name arguments body} { 
    uplevel 1 [list real_proc $name $arguments "global bar;$body"] 
} 

虽然这是相当讨厌的。