我想循环遍历一个或多个TCL数组,例如打印一个特定的值。
最好用代码来描述:
# Init
array unset one; array set one {param 1}
array unset two; array set two {param 2}
#Works fine
puts "one=$one(param)"
puts "two=$two(param)"
#Nope
foreach ar "one two" {puts ${$ar(param)}}
#Works, but makes a copy.
foreach tmp "one two" {
array unset ar
array set ar [array get $tmp]
puts "$tmp=$ar(param)"
}
这个"工作"的情况会产生一个副本(我想这没什么大不了的),但它看起来不正确。我更喜欢有一些更干净的东西,比如"Nope"情况(但它可以工作:)。
我同意这很丑。做这类事情的最好方法是使用局部变量别名。
foreach arrayName {one two} {
upvar 0 $arrayName ar
puts "$arrayName=$ar(param)"
}
您建议最好在过程中完成,因为您无法真正撤消变量混叠。这可以使upvar
的使用更加常规。
proc printEntry {entry args} {
foreach arrayName $args {
# Use [upvar 1] because we want the caller's name
upvar 1 $arrayName ar
puts "$arrayName=$ar($entry)"
}
}
printEntry param one two
(如果您使用upvar
,请始终使用级别参数-上面的0
和1
-以避免一些丑陋的错误解析问题)
如果您真的想让Nope情况起作用,另一种解决方案是记住$x
只是[set x]
和set
的简写,作为一个合适的命令,CC_6与tcl语法的其余部分比$
更好。
因此,将双upvar 0
0重新表述为set
,我们得到了这个工作代码:
foreach ar "one two" {puts [set [set ar](param)]}
第一轮替换,[set ar]
仅仅用值"one"或"two"替换ar
。在这种情况下,set
相对于$
的优势在于,它让程序员能够控制在哪里停止替换。我们可以选择[set ar(param)]
和$ar(param)
一样也可以选择[set ar](param)
,这是我们想要的
或者,您可以更改您的数据结构:
# Init
array set a {
"one,param" 1
"two,param" 2
}
puts "one=$a(one,param)"
puts "two=$a(two,param)"
foreach key {one two} {puts $a($key,param)}