我想将在一个函数中获得的变量参数传递给其他函数,但我无法这样做。函数获得偶数个变量参数,然后必须在数组中转换。以下是示例。
过程abc1
得到两个参数(k k
)而不是abc1
过程,这些过程必须传递给proc abc
,其中列表要进行数组转换。列表到数组转换在proc1中工作,即abc1
,但不在第二个proc中,即abc
获得的错误在下面给出
proc abc {args} {
puts "$args"
array set arg $args
}
proc abc1 {args} {
puts "$args"
array set arg $args
set l2 [array get arg]
abc $l2
}
abc1 k k
abc k k
输出:
k k
{k k}
list must have an even number of elements
while executing
"array set arg $l1"
(procedure "abc" line 8)
invoked from within
"abc $l2"
(procedure "abc1" line 5)
invoked from within
"abc1 k k"
(file "vfunction.tcl" line 18)
答案 0 :(得分:13)
正确的方法是确保外部过程(以堆栈术语)正确地调用内部过程;如果预期有多个参数,那就是应该提供的参数。随着Tcl 8.5的出现,使用一种称为 扩展替换 的语言语法很简单:
proc abc1 {args} {
puts "$args"
array set arg $args
set l2 [array get arg]
abc {*}$l2
# Or combine the two lines above into: abc {*}[array get arg]
}
所有{*}
所做的就是说该单词的其余部分应该被拆分(使用列表语法规则)并用作多个参数而不是Tcl的默认“一个可视单词构成单个单词”规则。这是理想的。
如果由于某种原因(即Tcl 8.4或更早版本)仍在使用旧版本的Tcl,那么您使用eval
命令而不是上述语法:
eval abc $l2
对于上述eval
,有一些更有效的方法,您可能会在旧代码中看到这些方法;例如:
eval [linsert $l2 0 abc]
eval [list abc] [lrange $l2 0 end]
# ... etc ...
但实际上它们都被abc {*}$l2
淘汰了,它更短,更简单,写得更快。 (它仅在8.4或之前不可用,并且有太多部署尚未升级。)如果可以,请使用扩展语法。确实,8.5及更高版本的惯用Tcl代码几乎不需要{{1 }};事实证明这一点已经证明是正确的,这对语言的维护者来说甚至是相当令人惊讶的。
答案 1 :(得分:1)
之间存在很大差异
abc k k
和
abc [array get arg]
在第一种情况下,您传递两个参数,每个参数都是k
。在第二种情况下,您传递的是列表 - 在您的示例中,列出了两个k:k k
。
Nir的answer明知无误地解决了这个问题,但更好的解决方案是编写abc1
以便正确调用abc
:
proc abc1 {args} {
array set arg $args
set l2 [array get arg]
eval abc $l2
# or just
# eval abc $args
}
答案 2 :(得分:-1)
当您通过abc $l2
时,您将abc1的args
作为单个参数传递给abc
。因此,在abc
args
中包含一个包含单个项目的列表({k k}
)。
您可以这样做:
proc abc {args} {
#the next line assumes that if $args has only a single item, then it is
#a list in itself. It's a risky decision to make but should work here.
if { [llength $args] == 1 } { set args [lindex $args 0] }
puts "$args"
array set arg $args
}