TCL / Expect变量vs $ variable

时间:2015-01-21 16:45:05

标签: variables tcl expect

使用variable使用或不使用美元符号的正确方法是哪一种?我认为variable(没有$)仅在variable声明期间使用(类似于Bash):

set var 10

在引用或使用(但未声明)variable的所有其他情况下,正确的语法为$variable$}:

set newVar $var
puts $var
puts $newVar

但后来我找到了互换的代码,似乎这段代码正在运行:

# using argv
if {[array exists argv]} {
  puts "argv IS ARRAY"
} else {
  puts "argv IS NOT AN ARRAY"
}

# using $argv
if {[array exists $argv]} {
  puts "\$argv IS ARRAY"
} else {
  puts "\$argv IS NOT AN ARRAY"
}

# using argv
if {[string is list argv]} {
  puts "argv IS LIST"
} else {
  puts "argv IS NOT LIST"
}

# using $argv    
if {[string is list $argv]} {
  puts "\$argv IS LIST"
} else {
  puts "\$argv IS NOT LIST"
}

输出:

argv IS NOT AN ARRAY
$argv IS NOT AN ARRAY
argv IS LIST
$argv IS LIST

编辑回复@glenn jackman:

您的回复指出我需要进一步研究,并且我发现TCL能够做某种自我修改代码"或者任何正确的名称,例如:

% set variableName "x"
x
% puts $x
can't read "x": no such variable
% set $variableName "abc"
abc
% puts $x
abc
% puts [set $variableName]
abc
%
%
%
%
%
%
% set x "def"
def
% puts $x
def
% puts [set $variableName]
def
%

现在你的答案为问题带来了一些启示,但还有一个问题。这是摘自文档:

set varName ?value?
array exists arrayName

文档说两个函数都期望变量名(而不是值),换句话说它期望variable而不是$variable。所以我假设(基于上面的自修改代码)当我通过$variable而不是variable时,发生了变量替换(与上面的代码完全相同)。但是如果$variable包含的东西不是列表也不是数组(我在测试期间的参数是:param0 param1" param 2" param3)。从这个角度来看,$argv IS LIST的输出是错误的。我在这里缺少什么?

编辑回复@schlenk:

最后我(希望)了解问题。我找到了关于TCL的great article,这解释了(不仅仅是)这个问题。让我从这篇文章中找出一些明智的陈述:

  • 在Tcl中,字符串表示的是由命令决定的 操纵它。
  • Tcl中的一切都是命令 - 你可以看到没有 赋值运算符。
  • if是一个带有两个参数的命令。
  • 命令名称不是特殊类型,只是一个字符串。

同样following SO answer 确认了这一陈述:

"在Tcl中,值不具有类型......他们的问题是它们是否可以用作给定类型。" 命令string is integer $a表示:

  • "我可以将$a中的值用作整数"

不会

  • " $a中的值是否为整数"

  • "每个整数也是一个有效的列表(一个元素)......所以它可以 用作任何一个和两个字符串是命令将返回true(如此 其他几个整数)。"

我认为同样适用于string is list命令:

% set abc "asdasd"
asdasd
% string is list $abc
1
% string is alnum $abc
1

string is list返回1,因为$abc是字符串,也是一个元素列表等。在大多数教程中,有人说下面的代码片段是声明和使用列表的正确方法:

% set list1 { 1 2 3 }
% lindex $list1 end-1
2

但是当TCL中的所有内容都是字符串时,以下内容也符合我的经验(如果我错了请纠正我)。

% set list2 "1 2 3"
1 2 3
% lindex $list2 end-1
2

2 个答案:

答案 0 :(得分:2)

这取决于命令。如果需要修改变量的内容,某些Tcl命令需要变量 name 作为参数。有些是:

  • 设置
  • 的foreach
  • lappend
  • 增量

大多数但肯定不是所有命令都想要获取变量的

您需要检查相关命令的documentation以查看参数是否包含“ varName ”(或“ dictionaryVariable ”),或者如果参数命名为“ string ”,“ list ”等,


使用带有 varName 参数的info exists的示例:

% set argv {foo bar baz}
foo bar baz
% info exists argv              ;# yes the variable "argv" exists
1
% info exists $argv             ;# no variable named "foo bar baz"
0
% set {foo bar baz} "a value"   ;# create a variable named "foo bar baz"
a value
% info exists $argv             ;# so now that variable exists
1

答案 1 :(得分:1)

重要的是要知道Tcl中的$x只是命令set x的语法糖。因此,您可以将Tcl代码中的任何$x转换为同一位置的[set x],以查看实际发生的情况。

要考虑的另一个重要事项是不可变的值。 Tcl值是不可变的,因此您无法更改它们。您只需创建一个新的更改值即可。但是你可以更改存储在变量中的值。

这是采用变量名的命令和带值的命令之间的区别。如果命令想要更改存储在变量中的值,则它采用变量名。示例包括lappendlsetappend等。其他命令返回一个新值并将值作为参数,示例包括lsortlsearchlindex

另一个重点是您实际上没有列表类型。你有像列表一样的字符串。这就是Tcl的string is list测试。这有一些后果,例如你不能总是决定你是否有一个字符串文字或一个项目列表,因为它通常是相同的。给出的例子:

% set maybe_list a
% string is list $maybe_list
1

将它与Tcls几乎不受限制的变量名称相结合,正如Glenn已经证明的那样,你可能会非常困惑。例如,这些都是有效的Tcl变量名称,您不能将它们全部用于$快捷方式:

% set "" 1       ;# variable name is the empty string
1
% puts [set ""]
% set " " 1      ;# variable name is just whitespace
1
% puts [set " "]
1
% set {this is a list as variable name} 1 ;# a variable with a list name
1
% puts [set {this is a list as variable name}]
1
% set Δx 1 
1
% incr Δx
2
% puts [set Δx]
2