我碰巧碰到了这个:
set a(()) 100
它由TCL解释器获取并添加到数组a
中,其索引为()且值为100的元素。
我很困惑。 official TCL spec对数组索引没有多说,它可以占用任何字符。那样就好。问题是,如何检索它?
puts $a(())
不起作用:
can't read "a(()": no such element in array
解决方法是:
set i ()
puts $a($i)
或
puts [set a(())]
我正在打败自己,以便明白为什么$a(())
在" a(())
"很高兴,但找不到任何。
答案 0 :(得分:5)
a(())
是数组成员的有效名称,正如您所说,我们可以使用set
分配给它并检索其值:
set a(()) 100
set a(())
当调用set
命令时,就像所有命令一样,解释器首先将命令行拆分为单词,根据需要执行替换,然后将这些单词作为参数传递给命令。 set
的第一个参数是变量名:set
命令使用与名称关联的变量或在分配时创建新变量,如果找不到任何此类变量,则会引发错误检索。
$
语法主要是单参数set
的语法糖,但不一定只使用一个命令行字来表示变量名。当解释器找到未转义的$
时,它会尝试查找构成变量名的字符序列,然后将变量的值替换为$
和名称。在此之后,该单词可以包含更多文本,并且该单词不必以$
开头。
解释器注意不要过度匹配,因此只允许一组有限的字符,一旦发现非法字符,它就会停止并尝试使用它找到的内容进行替换。如果找到一个左括号,匹配会稍微放宽(因为它可以期望以右括号的形式找到结束标记),这样就可以在索引中执行不同类型的替换(这就是为什么{{1工作)。
在这种情况下,如果单词结束(即找到空格;替换将因格式错误的变量名称而失败)或找到右括号,则匹配停止。这就是set i () ; puts $a($i)
失败的原因:解释器尝试使用$a(())
作为变量名,然后使用a(()
作为单词中的下一个字符。 )
确实有效,因为转义第一个右括号会否定其句法意义。
如果$a((\))
之后的第一个字符是左括号,则匹配右括号之前的所有字符都将用作变量名,这意味着括号内不能有匹配的闭括号,但几乎没有什么都可以。这意味着$
也可以。
答案 1 :(得分:1)
问题是,如何检索它?
问题恰恰在于$
语法是限制性的。您无法使用$
表单编写元素名称的合法值(例如,()}{()
将非常混淆解析器!)在这些情况下,您需要使用您列出的替代技术之一。这通常不是一个问题,因为这些尴尬的案件出现的地方是你没有脚本控制下的元素 - 因为你为什么故意选择让自己尴尬? - 然后你正在做一些事情,比如迭代你用array names
看过的一组名字,在这种情况下你已经得到了一个变量中的值并且没有问题。
有几种方法可以检索该值。以下是我推荐的(没有特别的顺序):
set theValueIs [set a(())]
set theElementIs (); set theValueIs $a($theElementIs)
upvar 0 a(()) alias; set theValueIs $alias
还有这个,它有效但不太符合我的口味:
set theValueIs ${a(())}