无法读取:变量不是数组 [英] can't read : variable isn't array

查看:286
本文介绍了无法读取:变量不是数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

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):变量不是数组。您能否建议导致错误的原因以及如何解决该错误。

but when I run the tcl script it fails for the line "set d1 $ar($key)" . The error msg is 'can't read "ar(a1)": variable isn't array' . Can you please suggest what is causing the error and how do I resolve the same.

推荐答案

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

When you use the syntax $ar($key), you are looking up the key $key in the array ar and returning its value. This is how Tcl is defined to work, it's in the basic language syntax. However, you're using the ar variable to hold a scalar value, not an array (the two are completely separate; arrays aren't values, though lists and dictionaries are). That's why you're getting the error message.

要从变量中命名的数组中读取数据,您要么需要使用更长的语法,要么替换变量名,然后从该变量中读取(默认情况下,Tcl不会为您执行此操作,因为如果您不准备这样做就非常危险),或者您需要为命名数组变量创建别名。

To read from an array that is named in a variable, you either need to use a longer piece of syntax so that you substitute the variable name and then read from that variable (Tcl doesn't do this for you by default, since it's quite dangerous if you're not prepared for it) or you need to make an alias to the named array variable.

set d1 [set ${ar}($key)]

$…实际上(实际上是)带有单个参数的 set 的别名。 (好吧,除了它实际上没有 调用命令;它们都调用相同的C API。)我们使用 $ {...} 格式以限制初始 $ 用作变量名的方式。请注意,如果将数组元素名称放在 ar 中,将会得到奇怪的结果。

This works because $… is really (under the hood) an alias for set with a single argument. (Well, except that it doesn't actually call the command; they both call the same C API.) We use the ${...} form to limit what the initial $ uses as its variable name. Be aware that if you put an array element name in ar, you'll get odd results from this.

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

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

The upvar command links variables together, and in particular when used with 0 as its first argument, it aliases variables in the current scope. By establishing theAlias as a fixed alias to the actual array (the one named by $ar), we can then access it just like a normal array. You could also alias directly to an element:

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

请注意与 set 解决方案;我们想要元素的名称,而不是读取它。 (警告:不要为全局 env 数组的元素加上别名;耦合到系统环境变量的代码不能以友好的方式与别名一起使用。)

Note the same syntax as used with the set solution above; we want the name of the element, not to read it. (Warning: do not alias to elements of the global env array; the code that couples to the system environment variables does not work in a friendly way with aliases.)

使用 upvar 的主要问题是您不能打开 theAlias 返回非别名变量(尽管您可以通过再次调用 upvar 来重新定位别名),而不是丢弃当前的堆栈帧(对于过程主体而言这是微不足道的,对于通过 namespace delete 命名空间来说,不是太难,但是对于全局命名空间而言,由于删除会终止整个Tcl解释器而引起问题。

The main issue with using upvar is that you can't turn theAlias back into a non-aliased variable (though you can retarget the alias by calling upvar again) other than by throwing away the current stack frame (trivial for a procedure body, not too hard for a namespace via namespace delete, but problematic with the global namespace as deleting that terminates the whole Tcl interpreter).

这篇关于无法读取:变量不是数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆