如何在 TCL 中动态创建数组并赋值



我想动态创建数组并为其赋值。

set num 0
foreach i {1 2 3} {
set count$i(sp) {$num}
incr num
set count$i(ep) [expr $num+1]
}

当我运行您的示例代码时,出现了此错误:

can't read "i(sp)": variable isn't array

这是因为count$i(sp)$i(sp)部分看起来像是对现有数组i的引用。

您需要使用大括号将$i(sp)隔离开来:

set num 0
foreach i {1 2 3} {
set count${i}(sp) {$num}
incr num
set count${i}(ep) [expr $num+1]
}

这将创建三个数组:

tcl8.6.8> parray count1
count1(ep) = 2
count1(sp) = $num
tcl8.6.8> parray count2
count2(ep) = 3
count2(sp) = $num
tcl8.6.8> parray count3
count3(ep) = 4
count3(sp) = $num

请注意,$num周围的大括号使用文字字符串$num。 您需要删除这些大括号:

set num 0
foreach i {1 2 3} {
set count${i}(sp) $num
incr num
set count${i}(ep) [expr $num+1]
}
tcl8.6.8> parray count1
count1(ep) = 2
count1(sp) = 0
tcl8.6.8> parray count2
count2(ep) = 3
count2(sp) = 1
tcl8.6.8> parray count3
count3(ep) = 4
count3(sp) = 2

但是,请准确解释"动态创建 Tcl 数组"的含义。 您真的想要三个单独的数组,还是可以拥有一个具有更多名称的数组,如下所示:

set num 0
foreach i {1 2 3} {
set count($i,sp) $num
incr num
set count($i,ep) [expr $num+1]
}
tcl8.6.8> parray count
count(1,ep) = 2
count(1,sp) = 0
count(2,ep) = 3
count(2,sp) = 1
count(3,ep) = 4
count(3,sp) = 2

如果你可以避免使用这样的动态变量名称,那就这样做;它们通常比它们的价值更麻烦。(您可以改用"复合"元素名称,如$i,sp。否则,也许是因为访问数组的其他代码,处理它们的最简单方法是使用upvar为具有固定名称的变量创建别名。 特别是,upvar 0为同一范围内的变量创建别名:

set num 0
foreach i {1 2 3} {
upvar 0 count$i ary
set ary(sp) {$num}
incr num
set ary(ep) [expr $num+1]
}

upvar 0的唯一问题是您无法真正撤消它;这就是为什么您几乎总是只在过程中使用它,因此当过程退出时,别名自然消失。

变量别名在过程上下文中非常有效,比在多个位置使用复合变量名称要高效得多。


另外,{$num}看起来很可疑。这不是错误的代码,因为它有一个正确的解释,但可能不会做你期望的事情,并且通常表明存在问题,因为$num没有被替换。您可能更喜欢[list $num].

您可能喜欢使用dict而不是array

set count {}
set num 0
foreach i {1 2 3} {
dict set count $i sp $num
incr num
dict set count $i ep [expr {$num + 1}]
}
set count               ;# -> 1 {sp 0 ep 2} 2 {sp 1 ep 3} 3 {sp 2 ep 4}
dict get $count 3 ep    ;# -> 4

最新更新