# Tcl 中的控制流

> 原文： [https://zetcode.com/lang/tcl/flowcontrol/](https://zetcode.com/lang/tcl/flowcontrol/)

在 Tcl 教程的这一部分中，我们将讨论流控制。 我们将定义几个命令，这些命令使我们能够控制 Tcl 脚本的流程。

在 Tcl 语言中，有几个命令可用于更改程序流程。 运行程序时，其命令从源文件的顶部到底部执行。 逐一。 可以通过特定命令更改此流程。 命令可以多次执行。 有些命令是有条件的。 仅在满足特定条件时才执行它们。

## `if`命令

`if`命令具有以下一般形式：

```tcl
if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?

```

`if`命令用于检查表达式是否为真。 如果为真，则执行命令主体。 主体用花括号括起来。

`if`命令计算一个表达式。 该表达式必须返回一个布尔值。 在 Tcl 中，1，是，`true`表示`true`，0，`no`，`false`表示`false`。

```tcl
!/usr/bin/tclsh

if yes {
    puts "This message is always shown"
}

```

在上面的示例中，始终执行由`{ }`字符包围的主体。

```tcl
#!/usr/bin/tclsh

if true then {
    puts "This message is always shown"
}

```

`then`命令是可选的。 如果我们认为可以使用它，它将使代码更加清晰。

我们可以使用`else`命令创建一个简单的分支。 如果`if`命令后方括号内的表达式的计算结果为`false`，则将自动执行`else`命令后方的命令。

```tcl
#!/usr/bin/tclsh

set sex female

if {$sex == "male"} {

    puts "It is a boy"
} else {

    puts "It is a girl"
}

```

我们有性别变量。 它具有“女性”字符串。 布尔表达式的计算结果为`false`，我们在控制台中得到“`It is a girl`”。

```tcl
$ ./girlboy.tcl 
It is a girl

```

我们可以使用`elseif`命令创建多个分支。 仅当不满足先前条件时，`elseif`命令才会测试其他条件。 请注意，我们可以在测试中使用多个`elseif`命令。

```tcl
#!/usr/bin/tclsh

# nums.tcl

puts -nonewline "Enter a number: "
flush stdout
set a [gets stdin]

if {$a < 0} {

    puts "the number is negative"
} elseif { $a == 0 } {

    puts "the numer is zero"
} else {

    puts "the number is positive"
}

```

在上面的脚本中，我们提示您输入一个值。 我们测试该值是否为负数或正数或等于零。 如果第一个表达式的计算结果为`false`，则对第二个表达式进行计算。 如果不满足先前的条件，则将执行`else`命令之后的主体。

```tcl
$ ./nums.tcl 
Enter a number: 2
the number is positive
$ ./nums.tcl 
Enter a number: 0
the numer is zero
$ ./nums.tcl 
Enter a number: -3
the number is negative

```

多次运行该示例。

## `switch`命令

`switch`命令将其字符串参数与每个模式参数按顺序进行匹配。 一旦找到与字符串匹配的模式，它就会通过将其递归传递给 Tcl 解释器来求值以下主体参数，并返回该求值结果。 如果最后一个模式参数为默认值，则它匹配任何内容。 如果没有任何模式参数与字符串匹配，并且没有给出默认值，那么`switch`命令将返回一个空字符串。

```tcl
#!/usr/bin/tclsh

# switch_cmd.tcl

puts -nonewline "Select a top level domain name:"
flush stdout

gets stdin domain

switch $domain {

    us { puts "United States" }
    de { puts Germany }
    sk { puts Slovakia }
    hu { puts Hungary }
    default { puts "unknown" }
}

```

在脚本中，我们提示您输入域名。 有几种选择。 例如，如果该值等于我们，则将“美国”字符串打印到控制台。 如果该值与任何给定值都不匹配，那么将执行默认主体，并将`unknown`打印到控制台。

```tcl
$ ./switch_cmd.tcl 
Select a top level domain name:sk
Slovakia

```

我们已将`sk`字符串输入到控制台，该程序响应了斯洛伐克。

## `while`命令

`while`命令是一个控制流命令，它允许根据给定的布尔条件重复执行代码。

`while`命令在大括号括起来的块内执行命令。 每次将表达式求值为`true`时都将执行命令。

```tcl
#!/usr/bin/tclsh

# whileloop.tcl

set i 0
set sum 0

while { $i < 10 } {

    incr i
    incr sum $i
}

puts $sum

```

在代码示例中，我们从一系列数字计算值的总和。

`while`循环包含三个部分：初始化，测试和更新。 该命令的每次执行都称为一个循环。

```tcl
set i 0

```

我们启动`i`变量。 它用作计数器。

```tcl
while { $i < 10 } {
...
}

```

`while`命令后面大括号内的表达式是第二阶段，即测试。 执行主体中的命令，直到表达式的计算结果为`false`。

```tcl
incr i

```

`while`循环的最后第三阶段是更新。 计数器增加。 请注意，对`while`循环的不正确处理可能会导致循环不断。

## `for`命令

如果在启动循环之前知道周期数，则可以使用`for`命令。 在此构造中，我们声明一个计数器变量，该变量在每次循环重复期间都会自动增加或减少值。

```tcl
#!/usr/bin/tclsh

for {set i 0} {$i < 10} {incr i} {
    puts $i
}

```

在此示例中，我们将数字`0..9`打印到控制台。

```tcl
for {set i 0} {$i < 10} {incr i} {
    puts $i
}

```

分为三个阶段。 首先，我们将计数器`i`初始化为零。 此阶段仅完成一次。 接下来是条件。 如果满足条件，则执行`for`块中的命令。 然后进入第三阶段； 计数器增加。 现在，我们重复阶段 2 和 3，直到不满足条件并留下`for`循环。 在我们的情况下，当计数器`i`等于 10 时，`for`循环停止执行。

```tcl
$ ./forloop.tcl 
0
1
2
3
4
5
6
7
8
9

```

在这里，我们看到`forloop.tcl`脚本的输出。

## `foreach`命令

`foreach`命令简化了遍历数据集合的过程。 它没有明确的计数器。 它逐个元素地遍历一个列表，并且当前值被复制到构造中定义的变量中。

```tcl
#!/usr/bin/tclsh

set planets { Mercury Venus Earth Mars Jupiter Saturn
    Uranus Neptune }

foreach planet $planets {
    puts $planet
}

```

在此示例中，我们使用`foreach`命令浏览行星列表。

```tcl
foreach planet $planets {
    puts $planet
}

```

`foreach`命令的用法很简单。 `planets`是我们迭代的列表。 `planet`是具有列表中当前值的临时变量。 `foreach`命令遍历所有行星并将其打印到控制台。

```tcl
$ ./planets.tcl 
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

```

运行上面的 Tcl 脚本将给出此输出。

```tcl
#!/usr/bin/tclsh

set actresses { Rachel Weiss Scarlett Johansson Jessica Alba \
    Marion Cotillard Jennifer Connelly}

foreach {first second} $actresses {
    puts "$first $second"
}

```

在此脚本中，我们迭代列表的值对。

```tcl
foreach {first second} $actresses {
    puts "$first $second"
}

```

我们在每次迭代时从列表中选择两个值。

```tcl
$ ./actresses.tcl 
Rachel Weiss
Scarlett Johansson
Jessica Alba
Marion Cotillard
Jennifer Connelly

```

这是`actresses.tcl`脚本的输出。

```tcl
#!/usr/bin/tclsh

foreach i { one two three } item {car coins rocks} {
    puts "$i $item"
}

```

我们可以并行遍历两个列表。

```tcl
$ ./parallel.tcl 
one car
two coins
three rocks

```

这是`parallel.tcl`脚本的输出。

## `break`和`continue`命令

`break`命令可用于终止由`while`，`for`或`switch`命令定义的块。

```tcl
#!/usr/bin/tclsh

while true {

    set r [expr 1 + round(rand()*30)]
    puts -nonewline "$r "

    if {$r == 22} { break }
}

puts ""

```

我们定义了一个无限的`while`循环。 我们使用`break`命令退出此循环。 我们从 1 到 30 中选择一个随机值并打印出来。 如果该值等于 22，则结束无穷`while`循环。

```tcl
set r [expr 1 + round(rand()*30)]

```

在这里，我们计算出 1..30 之间的随机数。 `rand()`是内置的 Tcl 过程。 它返回一个从 0 到 0.99999 的随机数。 `rand()*30`返回 0 到 29.99999 之间的随机数。 `round()`过程将最终数字四舍五入。

```tcl
$ ./breakcommand.tcl 
28 20 8 8 12 22 

```

我们可能会得到这样的东西。

`continue`命令用于跳过循环的一部分，并继续循环的下一个迭代。 可以与`for`和`while`命令结合使用。

在下面的示例中，我们将打印一个数字列表，这些数字不能除以 2 而没有余数。

```tcl
#!/usr/bin/tclsh

set num 0

while { $num < 100 } {

    incr num

    if {$num % 2 == 0} { continue }

    puts "$num "
}

puts ""

```

我们使用`while`循环遍历数字`1..99`。

```tcl
if {$num % 2 == 0} { continue }

```

如果表达式`num % 2`返回 0，则所讨论的数字可以除以 2。执行`continue`命令，并跳过循环的其余部分。 在我们的情况下，循环的最后一个命令将被跳过，并且数字不会打印到控制台。 下一个迭代开始。

在 Tcl 教程的这一部分中，我们正在讨论控制流结构。