遍历多个TCL数组

遍历多个TCL数组,tcl,Tcl,我想循环一个或多个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 ma

我想循环一个或多个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)"
}

那个“有效”的案例产生了一个副本(我想这没什么大不了的),但它看起来并不正确。我更喜欢一些更干净的东西,比如“不”的箱子(但它是有效的:)。

我同意这很难看。最好的方法是使用局部变量别名。您可以使用
upvar 0
制作这些

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
,以避免一些难看的错误解析问题。)

我同意这是难看的。最好的方法是使用局部变量别名。您可以使用
upvar 0
制作这些

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
,请始终使用上面的level参数-
0
1
,以避免一些难看的错误解析问题。)

如果您真的想让Nope案例起作用,另一种解决方案是记住
$x
只是
[set x]的简写
set
,作为一个合适的命令,它比仅仅是语法的
$
更好地使用了tcl语法的其余部分

因此,将您的双精度
$$
重新格式化为
集合
将为我们提供以下工作代码:

foreach ar "one two" {puts [set [set ar](param)]}

第一轮替换,
[set ar]
仅将
ar
替换为值“一”或“二”。在这种情况下,
set
$
的优势在于,它让程序员能够控制在何处停止替换。我们可以做与
$ar(param)
相同的
[set ar(param)]
,或者我们可以更早地停止:
[set ar](param)
,这就是我们在这种情况下想要的。

如果你真的想让Nope案例起作用,另一种解决方案是记住
$x
只是
[set x]的简写
set
,作为一个合适的命令,它比仅仅是语法的
$
更好地使用了tcl语法的其余部分

因此,将您的双精度
$$
重新格式化为
集合
将为我们提供以下工作代码:

foreach ar "one two" {puts [set [set ar](param)]}

第一轮替换,
[set ar]
仅将
ar
替换为值“一”或“二”。在这种情况下,
set
$
的优势在于,它让程序员能够控制在何处停止替换。我们可以执行与
$ar(param)
相同的
[set 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)}

或者,您可以更改数据结构:

# 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)}

实际上,第二个
集合
是不必要的。您可以像这样编写
foreach ar“一两”{put“$ar=[set${ar}(param)]”}
$foo
不是
set foo
的缩写。请参见
trace
@JohannesKuhn:“$foo是[set foo]的缩写”这句话是用来解释tcl替代规则的传统说法。此外,为了
trace
的目的,
$foo
set foo
都触发变量跟踪(虽然显然只有
set foo
会触发
set
上的命令跟踪),实际上,第二个
set
是不必要的。您可以像这样编写
foreach ar“一两”{put“$ar=[set${ar}(param)]”}
$foo
不是
set foo
的缩写。请参见
trace
@JohannesKuhn:“$foo是[set foo]的缩写”这句话是用来解释tcl替代规则的传统说法。此外,为了<代码> Trace<代码> < <代码> $Fo< <代码>和>代码> SET FoO 触发器变量跟踪(虽然显然仅<代码> SET FoO 将触发命令跟踪在<代码> SET>代码>),我考虑DAONE研究员glenn jackman提供的所有答案,斯莱贝特曼要准确地回答我要做的事情的意图。我选择了@ SkyBeman,因为它最接近回答我的具体问题:我如何写“NoPE”的案例?我认为DANOL研究员、glenn jackman和SybBeman提供的所有答案都是正确的,并且正确地回答了我试图做的事情的意图。我之所以选择@slebetman,是因为它最接近于回答我的具体问题:我如何编写“否”案例?