TCL/Expect 变量与 $variable
TCL/Expect variable vs $variable
使用带美元符号或不带美元符号的 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 能够做某种 "self modifying code" 或任何正确的名称,例如:
% 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:
终于(希望)明白了问题所在。我发现 great article 关于 TCL,这解释了(不仅仅是)这个问题。让我从这篇文章中找出一些明智的说法:
- 在 Tcl 中,字符串代表什么取决于命令
操纵它。
- 在 Tcl 中一切都是命令 - 如您所见,没有
赋值运算符。
if
是一个命令,有两个参数。
- 命令名称不是特殊类型,只是一个字符串。
也following SO answer 证实了这个说法:
"In Tcl, values don't have a type... they question is whether they can be used as a given type."
命令string is integer $a
表示:
- "Can I use the value in
$a
as an integer"
不
"Is the value in $a
an integer"
"每个整数也是一个有效列表(一个元素)...所以它可以是
用作其中一个和两个字符串是命令将 return 为真(将
几个其他的整数)。"
我相信这同样适用于 string is list
命令:
% set abc "asdasd"
asdasd
% string is list $abc
1
% string is alnum $abc
1
string is list
returns 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
这取决于命令。一些 Tcl 命令需要一个变量 name 作为参数,如果它们需要 modify 变量的内容。一些是:
- 设置
- foreach
- lappend
- 增量
大多数但肯定不是所有命令都想获取变量的值。
您需要检查相关命令的 documentation 以查看参数是否包括“varName”(或“dictionaryVariable"),或者如果参数命名为“string”、“list”等
使用 info exists
的示例采用 varName 参数:
% 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
要知道的重要一点是 Tcl 中的 $x
只是命令 set x
的语法糖。所以你可以在同一个地方将 Tcl 代码中的任何 $x
翻译成 [set x]
,看看到底发生了什么。
另一个需要考虑的重要事项是不可变值。 Tcl 值是不可变的,因此您无法更改它们。您可以只创建一个新的更改值。但是您可以更改存储在变量中的值。
这就是使用变量名的命令和使用值的命令之间的区别所在。如果命令想要更改存储在变量中的值,它需要一个变量名。例如 lappend
、lset
、append
等。其他命令 return 一个新值并以一个值作为参数,示例包括 lsort
、lsearch
、lindex
.
另一个重要的一点是您实际上并没有列表类型。你有看起来像列表的字符串。这就是 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
使用带美元符号或不带美元符号的 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 能够做某种 "self modifying code" 或任何正确的名称,例如:
% 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:
终于(希望)明白了问题所在。我发现 great article 关于 TCL,这解释了(不仅仅是)这个问题。让我从这篇文章中找出一些明智的说法:
- 在 Tcl 中,字符串代表什么取决于命令 操纵它。
- 在 Tcl 中一切都是命令 - 如您所见,没有 赋值运算符。
if
是一个命令,有两个参数。- 命令名称不是特殊类型,只是一个字符串。
也following SO answer 证实了这个说法:
"In Tcl, values don't have a type... they question is whether they can be used as a given type."
命令string is integer $a
表示:
- "Can I use the value in
$a
as an integer"
不
"Is the value in
$a
an integer""每个整数也是一个有效列表(一个元素)...所以它可以是 用作其中一个和两个字符串是命令将 return 为真(将 几个其他的整数)。"
我相信这同样适用于 string is list
命令:
% set abc "asdasd"
asdasd
% string is list $abc
1
% string is alnum $abc
1
string is list
returns 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
这取决于命令。一些 Tcl 命令需要一个变量 name 作为参数,如果它们需要 modify 变量的内容。一些是:
- 设置
- foreach
- lappend
- 增量
大多数但肯定不是所有命令都想获取变量的值。
您需要检查相关命令的 documentation 以查看参数是否包括“varName”(或“dictionaryVariable"),或者如果参数命名为“string”、“list”等
使用 info exists
的示例采用 varName 参数:
% 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
要知道的重要一点是 Tcl 中的 $x
只是命令 set x
的语法糖。所以你可以在同一个地方将 Tcl 代码中的任何 $x
翻译成 [set x]
,看看到底发生了什么。
另一个需要考虑的重要事项是不可变值。 Tcl 值是不可变的,因此您无法更改它们。您可以只创建一个新的更改值。但是您可以更改存储在变量中的值。
这就是使用变量名的命令和使用值的命令之间的区别所在。如果命令想要更改存储在变量中的值,它需要一个变量名。例如 lappend
、lset
、append
等。其他命令 return 一个新值并以一个值作为参数,示例包括 lsort
、lsearch
、lindex
.
另一个重要的一点是您实际上并没有列表类型。你有看起来像列表的字符串。这就是 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