无法读取:变量不是数组

时间:2012-07-16 07:09:01

标签: arrays tcl

我有以下代码:

set arr1(a1) t1
set arr2(a2) t2
set l1 {}
lappend l1 arr1
lappend l1 arr2

set arr3(a3) $l1

foreach names [array names arr3] {
    set value $arr3($names)
    puts "names = $names, value = $value"
    foreach ar $value {
      if {[array exists $ar]} {
        puts "$ar is an array"
        foreach {key val} [array get $ar] {
          set d1 $ar($key)
          puts "ar key = $key value = $val "
        }
      }
    }
  }

但是当我运行tcl脚本时,对于“set d1 $ ar($ key)”这一行失败了。错误消息“无法读取”ar(a1)“:变量不是数组”。你能否说一下导致错误的原因以及如何解决这个问题。

1 个答案:

答案 0 :(得分:4)

当您使用语法$ar($key)时,您正在查找数组$key中的键ar并返回其值。这就是Tcl被定义为工作的方式,它是基本的语言语法。但是,您使用ar变量来保存标量值,而不是数组(两个完全分开;数组不是值,尽管列表和字典也是如此)。这就是你收到错误信息的原因。

要从变量中命名的数组中读取,您需要使用更长的语法,以便替换变量名,然后从该变量中读取(默认情况下,Tcl不会为您执行此操作,因为如果你没有做好准备就很危险,或者你需要为命名的数组变量做一个别名。

通过set

进行双重替换
set d1 [set ${ar}($key)]

这是有效的,因为$…实际上(在引擎盖下)是set的别名,只有一个参数。 (好吧,除了它实际上调用命令之外;它们都调用相同的C API。)我们使用${...}形式来限制初始$使用的内容作为其变量名称。请注意,如果将数组元素名称放在ar中,则会得到奇怪的结果。

别名阵列或元素

upvar 0 $ar theAlias
set d1 $theAlias($key)

upvar命令将变量链接在一起,特别是当与0一起使用作为其第一个参数时,它将变量置于当前作用域中。通过将theAlias建立为实际数组(由$ar命名的那个)的固定别名,我们就可以像普通数组一样访问它。您也可以直接对元素进行别名:

upvar 0 ${ar}($key) theAlias
set d1 $theAlias

请注意与上述set解决方案使用的语法相同的语法;我们想要元素的名称,而不是阅读它。 (警告:不要对全局env数组的元素进行别名;耦合到系统环境变量的代码不能以带有别名的友好方式工作。)

使用upvar的主要问题是您无法将theAlias变回非别名变量(尽管您可以通过再次调用upvar来重新定位别名)通过抛弃当前的堆栈帧(对于过程体来说是微不足道的,对于通过namespace delete的命名空间来说不是太难,但是对于全局命名空间有问题,因为删除会终止整个Tcl解释器。)

相关问题