在 Tcl 中使用方括号和 space 字符

Use of brackets and space character in Tcl

我仍然对括号的用法感到困惑,即 () [] 和 {} 在 Tcl 中的使用。我总是被抓到使用错误的括号,在需要使用它们时错过了括号或使用了太多括号。除此之外,我也对 Tcl 感到困惑,它根据是否存在 space 字符(在数学表达式中)以及如果我连续使用了多个 space 字符来给我不同的结果。

谁能告诉我摆脱困境必须牢记的基本规则。括号在 C 和其他一些语言中一直很容易使用,但在这里它们完全不同。

您不能将 Tcl 与 C 进行比较。在 C 中,{} 定义范围。在 Tcl 中,{} 是分组运算符。

在 Tcl 中,{} 可以对字符串进行分组:

 {hello world}

或列表:

 {a b c d e f g h}

或脚本:

 {
 puts -nonewline {hello }
 puts world\n
 }

每个命令都是简单的一系列组(可能是一个词,一个列表, 表达式或脚本):

 {if} {true} { puts "hello\n" }

当然,你不需要把每个单词都用大括号括起来, 但是您确实需要用大括号括起脚本:

 if true { puts hello\n }

通常,对于 if 语句,不支持表达式是个坏主意, 所以这样更好:

 if { true } { puts hello\n }

这个简单的规则创建了 Tcl 非常简单的语法。每个命令都很简单 一系列组,无论是单词、表达式、列表还是脚本:

 if expr script
 while expr script
 proc name argument-list script
 puts string
 for initialization condition nextloop script

要记住的一件重要事情是,每当需要一个表达式时,它 应该用大括号括起来,以防止过早替换。例如:

 set i 0
 while { $i < 10 } {
    incr i
 }

方括号 [] 替换为包含的命令的输出 通过方括号:

 set output [expr {2**5}]

像往常一样在表达式中使用括号:

 set output [expr {(2**5)+2}]

对于数组:

 set i 0
 while { $i < 5 } {
   set output($i) [expr {2**$i}]
   incr i
 }
 parray output

在您所看到的级别上,Tcl 非常 不同于您曾经使用过的任何其他语言。 Tcl 的核心由 Tcl(n) manual page 定义,其中指出(除其他事项外):

  • 空格分隔单词。每个命令都将其参数作为一个单词序列。换行符和分号分隔命令调用;它们是完全等价的,但好的风格是使用换行符而不是分号。
  • {大括号} 主要用于引用文本,以便将其传递给不进行替换或单词分隔的命令。 它们正确嵌套。 $ 后也使用大括号在少数情况下进行变量替换:这种用法很少见。
  • "双引号" 用于引用文本,以便将其传递给命令并应用 替换,但没有单词分隔。
  • [方括号]是命令替换。它们被括号内脚本 运行 的结果替换。脚本通常是单个命令。
  • (括号) 只有一种基本语言用途:用于(关联)数组元素。因此,$a(b) 是一个变量替换,它将使用 a 数组中 b 元素的值。

人们所说的 Tcl 的其余部分实际上只是一个标准库,一组让您入门的命令。有些是基本的。例如:

  • if 是条件命令,如果条件为真,则评估分支(脚本)。为了使其有意义,必须在评估和测试条件之前不评估分支;这几乎需要把它放在大括号中。

  • while 是一个循环命令,您不仅要支撑它的主体(这可能会被一遍又一遍地求值),而且您还想放置条件表达式在大括号中以及您肯定希望每次循环都重新评估它。

  • proc是一个可以让你自定义命令的命令。程序的主体肯定是您稍后要评估的东西;它放在大括号中。

  • expr 是一个通用的表达式求值命令。在所有正常情况下,您会希望将其表达式放在大括号中,以便代码可以编译并且不会出现双重替换问题。请注意,表达式经常大量使用括号:它们在表达式语法中具有额外的含义。特别是,除了数组元素查找外,它们还用于函数调用和分组。

    请注意 ifwhile 也使用相同的表达式计算引擎。他们只是使用表达式的结果来决定要做什么。

作用域由命令决定。处理引入作用域的常用命令是 procnamespace eval这与 C、C++、Java、C# 或 Javascript 完全不同; 它们有不同的规则。除非您明确说明,否则变量对于它们的过程是局部的。


社区的做法是这样调用:

if { $foo(bar) > (17 + $grill) * 7 } {
    # This is a comment; it lasts to the end of the line
    puts "the foobar $foo(bar) is too large"
    set foo(bar) [ComputeSmallerValue $grill]
}

也就是说,裸词(ifputs)是不带引号的,表达式和内部脚本是brace-quoted,在有意义的地方使用括号,但大多数用于数组和表达式,空格分隔为了清晰起见,所有单词、内部脚本都缩进(通常缩进 4)(它没有语义,但确实有助于阅读),并且“块”使用埃及大括号,这样您就不必在整个过程中添加反斜杠这个地方。

您不必遵守这些规则(它们是准则,而非法律),但如果您遵守这些规则,它们会让您的生活更轻松。有时你确实需要打破规则,但你应该知道要小心。