以下变量之间有什么区别:
$argv
$::argv
{*}$argv
Run Code Online (Sandbox Code Playgroud)
前两个可以通过puts命令打印,它们返回以下输出:
param0 param1 {param 2} param3
param0 param1 {param 2} param3
Run Code Online (Sandbox Code Playgroud)
传递给脚本的参数是:
param0 param1 "param 2" param3
Run Code Online (Sandbox Code Playgroud)
最后一个结果出现错误:
wrong # args: should be "puts ?-nonewline? ?channelId? string"
while executing
"puts {*}$argv"
Run Code Online (Sandbox Code Playgroud)
我使用以下代码在该领域做了一些研究:
if {[array exists $argv]} {
puts "\$argv IS ARRAY"
} else {
puts "\$argv IS NOT AN ARRAY"
}
if {[string is list $argv]} {
puts "\$argv IS LIST"
} else {
puts "\$argv IS NOT LIST"
}
if {[array exists $::argv]} {
puts "\$::argv IS ARRAY"
} else {
puts "\$::argv IS NOT AN ARRAY"
}
if {[string is list $::argv]} {
puts "\$::argv IS LIST"
} else {
puts "\$::argv IS NOT LIST"
}
if {[array exists {*}$argv]} {
puts "{*}\$::argv IS ARRAY"
} else {
puts "{*}\$::argv IS NOT AN ARRAY"
}
if {[string is list {*}$argv]} {
puts "{*}\$::argv IS LIST"
} else {
puts "{*}\$::argv IS NOT LIST"
}
Run Code Online (Sandbox Code Playgroud)
最后两个 if-else 语句包含{*}$argv以下错误:
wrong # args: should be "array exists arrayName"
while executing
"array exists {*}$argv"
invoked from within
"if {[array exists {*}$argv]} {
puts "{*}\$::argv IS ARRAY"
} else {
puts "{*}\$::argv IS NOT AN ARRAY"
}"
Run Code Online (Sandbox Code Playgroud)
注释掉这两个语句表明$argv和$::argv是列表:
argv IS NOT AN ARRAY
$argv IS NOT AN ARRAY
argv IS LIST
$argv IS LIST
Run Code Online (Sandbox Code Playgroud)
这两个列表都可以作为标准列表进行遍历,例如:
foreach item $argv {
puts $item
}
Run Code Online (Sandbox Code Playgroud)
或者
foreach item $::argv {
puts $item
}
Run Code Online (Sandbox Code Playgroud)
尝试以相同的方式遍历{*}$argv会再次导致以下错误:
wrong # args: should be "foreach varList list ?varList list ...? command"
while executing
"foreach item {*}$argv {
puts $item
}"
Run Code Online (Sandbox Code Playgroud)
我用的是TCL 8.5版本
\n\n以下变量之间有什么区别:
\nRun Code Online (Sandbox Code Playgroud)\n$argv\n$::argv\n{*}$argv\n
这里有两种类型的差异。
\n在 Tcl 中,非限定变量和限定变量可能有点不同,但这取决于上下文(尽管以一种非常简单的方式)。::首先,限定变量名是指其中至少包含一个的变量名。如果变量名(Tcl 中 \xe2\x80\x94 后面的内容,仅表示\xe2\x80\x9cread 这个变量并在此处使用其内容\xe2\x80\x9d)以 开头,则它是绝对变量名,否则限定变量名是相对变量名,并根据当前命名空间进行解析(如果不确定,可以使用该命名空间来查找)。在所有上下文中,绝对变量名始终指代相同的事物。因此,是一个绝对变量名,实际上它指的是在顶级全局命名空间中调用的变量。这恰好是一个变量,可以将它们的参数写入其中。$$::namespace current::argvargvtclshwish
但如果没有, ::则它是一个非限定变量名。如果您不在过程(或类似过程的事物中,其中包括 lambda 术语,例如您使用的apply或各种 OO 系统定义的方法),则该变量(大部分)将被视为相对变量名称并根据当前名称空间进行解析。namespace eval和namespace code是可以更改当前名称空间的两个内容(其他内容更加晦涩难懂)。所有这些都供您用来variable声明所有名称空间变量。否则,您可能会遇到一些非常令人讨厌的可变分辨率的奇怪问题。所以一定要使用variable. 真的。
但是,如果您处于过程(类似实体)中,则该非限定名称指的是局部变量,其生命周期与进入过程时压入堆栈的堆栈帧的生命周期耦合。可以通过各种命令链接到其他范围(包括全局命名空间)中的变量:global、upvar、variable和namespace upvar。然而,变量的实际分辨率是局部的。
最后,可能还存在一个自定义变量解析器。由于您使用的是 Tcl 8.5,因此您最有可能看到此功能的地方是使用 Incr Tcl(Tcl 的对象系统)。自定义变量解析器可以做一些复杂的事情。(如果您使用的是 Tcl 8.6,最有可能在工作中看到自定义变量解析器的地方是 TclOO。那里的变量解析器非常保守和谨慎,但允许将局部变量绑定到对象变量,而无需显式声明此变量在每个方法中)。
\n$argv和之间的区别{*}$argv是完全不同的。
$argv是正常的替换。它说\xe2\x80\x9cread这里变量并使用它的内容代替\xe2\x80\x9d。它可以用在单词的中间,$argv$argv$argv一个事物也是如此,由变量的内容串联argv三次组成。
{*},当放置在单词的开头时(在其他地方并不特殊),标记该单词以进行扩展。当一个单词被扩展时,在完成所有其他正常替换后,它会被解析为 Tcl 列表,并且该列表中的单词将用作正在构建的结果命令中的单词。{*}$argv是一种退化情况,其中单词的其余部分只是从变量中读取的内容;命令中使用的单词是变量中列表的元素argv。因为这通常是一个列表,所以这一切都很顺利。
这是一个例子:
\nset abc {a b c}\nset dabcf [list d $abc f]\nputs $dabcf; # ===> \xe2\x80\x9cd {a b c} f\xe2\x80\x9d\n\nset eabcg [list e {*}$abc g]\nputs $eabcg; # ===> \xe2\x80\x9ce a b c g\xe2\x80\x9d\nRun Code Online (Sandbox Code Playgroud)\n看到不同?一个在列表中生成三个元素,另一个生成五个。如果有更长的东西就更有意义了:
\nset options {\n -foreground blue\n -background yellow\n -text "This is eye-watering stuff!"\n}\nbutton .b1 {*}$options -command {puts "Ouch 1"}\nbutton .b2 {*}$options -command {puts "Ouch 2"}\nbutton .b3 {*}$options -command {puts "Ouch 3"}\npack .b1 .b2 .b3\nRun Code Online (Sandbox Code Playgroud)\n通过扩展,一切都可以正常工作\xe2\x84\xa2。如果没有,你就必须做一些可怕的事情eval:
eval [list button .b1] [lrange $options 0 end] [list -command {puts "Ouch 1"}]\n# etc.\nRun Code Online (Sandbox Code Playgroud)\n这很难做到正确,而且很乏味,所以它给很多人(包括 Tcl 和 Tk 维护者!)带来了很多问题,因为他们倾向于走捷径并出错。为了解决这个问题,Tcl 8.5 中创建了扩展语法,以减少所有错误的发生。(普通 Tcl 中的原型示例往往涉及 的内容exec,并且意味着很多人实际上因此而存在安全漏洞。)
作为奖励,使用{*}比使用快得多,eval因为扩展可以保证它永远不会对事物进行复杂的重新分析。在 Tcl 中,更快几乎总是与更安全相关。
请注意,这与变量是否合格无关。是的,这意味着{*}$::argv如果您愿意,您也可以拥有。