Tcl 8.4:展开作为过程参数的变量



我有一个问题Tcl 8.4.

我想要做的概念是这样的:

  • 一个现有的内置函数,builtinFn,有一个必需的参数,然后是可变数量的参数(实际需要的数量取决于第一个参数),所以它可以像builtinFn {arg_1a arg_1b} "two" "three" "four"一样被调用,说;
  • 我想提供一个包装函数,wrapperFn,它检查第一个参数,然后将其分解为其组成部分(上面的示例中的arg_1aarg_1b),然后分别使用第一个参数的每个单独组成部分调用builtinFn,如builtinFn {arg_1a} "two" "three" "four"builtinFn {arg_1b} "two" "three" "four"

无论我怎么尝试,我得到一个错误消息,"Error: wrong # args:";当我从wrapperFn内部调用builtinFn时。

问题的简化示例

proc myInternal {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" turquoise4;
}
proc myWrapper {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
myInternal $var1 $args
}

注意:无论你在哪里看到mess,请像puts一样阅读它-它只是以一种简洁的方式写入控制台,带有指定文本颜色的选项。

如果我调用myInternal one two three,那么输出是

var1 is one (length is 1), and args is two three  (length is 2).  

如果我调用myWrapper one two three,那么输出是

var1 is one (length is 1), and args is two three  (length is 2).  
var1 is one (length is 1), and args is {two three}  (length is 1).  

我看到了一些可能是相关的帖子。

  • TCL-如何将字符串解释为TCL过程中的多个参数?(重复)
  • TCL脚本:变量作为函数参数

也许这可以用Tcl 8.5中的{*}来解决,但目前我还没有。我还没有弄清楚如何实现它与任何其他选项,如listconcateval

我试过的其他一些方法都不奏效:

proc myWrapper2 {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
myInternal "$var1 $args"
}
myWrapper2 one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is one two three (length is 3), and args is   (length is 0).  
proc myWrapper3 {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
myInternal $var1 [split $args]
}
myWrapper3 one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is one (length is 1), and args is {two three}  (length is 1).  
proc myWrapper4a {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
myInternal [list $var1 $args]
}
myWrapper4a one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is one {two three} (length is 2), and args is   (length is 0).  
proc myWrapper4b {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
myInternal [concat $var1 $args]
}
myWrapper4b one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is one two three (length is 3), and args is   (length is 0).  
proc myWrapper5 {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
myInternal [puts "$var1 $args"]
}
myWrapper5 one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is  (length is 0), and args is   (length is 0).  
proc myWrapper6 {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
eval myInternal $var1 [split $args ,]
}
myWrapper6 one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is one (length is 1), and args is {two three}  (length is 1).  
proc myWrapper7 {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
eval myInternal [split "$var1 $args" ,]
}
myWrapper7 one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is one two three (length is 3), and args is   (length is 0).  
proc myWrapper8 {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
eval {myInternal [split "$var1 $args" ,]}
}
myWrapper8 one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is {one two three} (length is 1), and args is   (length is 0).  
proc myWrapper9 {var1 args} { 
mess "var1 is $var1 (length is [llength $var1]), and args is $args  (length is [llength $args]).  n" green4; 
eval [linsert {} 0 myInternal $var1 $args]
}
myWrapper9 one two three
# Output:  
# var1 is one (length is 1), and args is two three  (length is 2).  
# var1 is one (length is 1), and args is {two three}  (length is 1).  

如果它不是很明显,我需要第二个语句,这是由myInternal编写的(从myWrapper调用),完全匹配第一个语句,这是由myWrapper"直接"编写的。

谢谢你的建议!

div

如您所知,在Tcl 8.4中,您需要为此使用eval。为了合理地确保不会产生副作用,您需要向eval传递一个列表,该列表由命令的名称组成,后面跟着每个单独的参数。在您的示例中实现这一点的一种方法是:

eval [linsert $args 0 myInternal $var1]

在您的所有尝试中,您一直将args作为单个元素传递,或者使事情变得更糟。

使用concat的方法可以是:

eval [concat myInternal [list $var1] $args]

请注意,您必须在$var1附近使用list,以防止它可能包含的任何特殊字符造成破坏。例如:

myWrapper "hello world" two three
myWrapper \{ two three

基于勒布朗的答案,wrapperFn将是

proc wrapperFn {varlist args} {
foreach var $varlist {
eval [linsert $args 0 builtinFn $var]
}
}

最新更新