跳轉至內容

Raku 程式設計/控制結構

來自 Wikibooks,開放世界中的開放書籍

流控制

[編輯 | 編輯原始碼]

我們在前面的章節中已經瞭解瞭如何建立變數並使用它們來執行基本的算術運算和其他操作。現在我們將介紹流控制的概念,使用特殊的結構進行分支迴圈

塊是 { } 花括號內的程式碼塊。這些程式碼塊以多種方式與周圍程式碼分離。它們還為變數定義了一個新的作用域:用 my 定義並在塊內使用的變數在塊外不可見或不可用。這使得程式碼能夠被分隔,以確保僅用於臨時使用的變數只在臨時使用。

分支可以使用兩種語句之一進行:ifunlessif 可選擇地還具有 else 子句。if 語句評估給定的條件,如果它是真語句,則執行 if 後面的塊。當語句為假時,如果有,則改為執行 else 塊。unless 語句則相反。它評估一個條件,只有在條件為假時才執行其塊。使用 unless 時不能使用 else 子句。

關係運算符

[編輯 | 編輯原始碼]

有許多關係運算符可用於確定真值。以下是一些運算子

$x == $y;                  # $x and $y are equal
$x > $y;                   # $x is greater than $y
$x >= $y;                  # $x is greater than or equal to $y
$x < $y;                   # $x is less than $y
$x <= $y;                  # $x is less than or equal to $y
$x != $y;                  # $x is not equal to $y

所有這些運算子都返回布林值,並且可以分配給變數

$x = (5 > 3);              # $x is True
$y = (5 == 3);             # $y is False

上面的括號僅用於清晰度;它們實際上不是必需的。

if/unless

[編輯 | 編輯原始碼]

讓我們從一個例子開始

my Int $x = 5;
if ($x > 3) {
     say '$x is greater than 3';         # This prints
}
else {
     say '$x is not greater than 3';     # This doesn't
}

請注意,在上面的示例中,if($x > 3) 之間有一個空格。這一點很重要,不是可選的。Raku 的解析規則在這方面很明確:任何以 ( 開頭的括號結尾的詞都被視為子例程呼叫。空格將此語句與子例程呼叫區分開來,並讓解析器知道這是一個條件。

if($x > 5) {   # Calls subroutine "if"
}

if ($x > 5) {  # An if conditional
}

為了避免所有混淆,可以安全地省略括號。

if $x > 5 {     # Always a condition
}

unlessif 的行為相反

my Int $x = 5;
unless $x > 3 {
     say '$x is not greater than 3';         # This doesn't print
}

unless 後面不允許使用 else 子句。

字尾語法

[編輯 | 編輯原始碼]

ifunless 不僅對標記要條件執行的塊有用。它們還可以以自然的方式應用在語句的末尾,以僅影響該語句

$x = 5 if $y == 3;
$z++ unless $x + $y > 8;

上面的兩行程式碼僅在滿足其條件時才執行。第一行將 $x 設定為 5,如果 $y 等於 3。第二行遞增 $z,除非 $x + $y 的總和大於 8。

智慧匹配

[編輯 | 編輯原始碼]

有時您想檢查兩件事是否匹配。關係運算符 == 檢查兩個值是否相等,但這非常有限。如果我們想檢查其他相等關係怎麼辦?我們想要一個無論是什麼都做我們想做的事情的運算子。這個神奇的運算子就是智慧匹配運算子 ~~

現在,當您看到 ~~ 運算子時,您可能馬上想到字串。智慧匹配運算子對字串有很多用途,但並不侷限於字串。

以下是一些智慧匹配運算子在實際中的例子

5 ~~ "5";                          # true, same numerical value
["a", "b"] ~~ *, "a", *;           # true, "a" contained in the array
("a" => 1, "b" => 2) ~~ *, "b", *; # true, hash contains a "b" key
"c" ~~ /c/;                        # true, "c" matches the regex /c/
3 ~~ Int                           # true, 3 is an Int

正如您所見,智慧匹配運算子可以以多種方式使用來測試兩件事,以檢視它們是否以某種方式匹配。上面我們看到了正則表示式的示例,我們將在後面的章節中詳細討論。這也不是可以匹配事物的完整列表,我們將在整本書中看到更多內容。

Given / When

[編輯 | 編輯原始碼]

Raku 具有將數量與多個不同備選方案進行匹配的功能。該結構是 givenwhen 塊。

given $x {
  when Bool { say '$x is the boolean quantity ' ~ $x; }
  when Int { when 5 { say '$x is the number 5'; } }
  when "abc" { say '$x is the string "abc"'; }
}

每個 when 都是一個智慧匹配。上面的程式碼等效於以下程式碼

if $x ~~ 5 {
  say '$x is the number 5';
} 
elsif $x ~~ "abc" {
  say '$x is the string "abc"';
}
elsif $x ~~ Bool {
  say '$x is the boolean quantity ' ~$x;
}

given/when 結構比 if/else 更簡潔,並且在內部,它可能以更最佳化的方式實現。

迴圈是重複執行某些語句組多次的方法。Raku 有多種可用的迴圈型別,每種型別都有不同的用途。

for 迴圈

[編輯 | 編輯原始碼]

for 塊接受陣列或範圍作為引數,並遍歷每個元素。在最基本的情況下,for 將每個連續的值分配給預設變數 $_。或者,可以列出特定變數來接收值。以下是一些 for 塊的例子

# Prints the numbers "12345"
for 1..5 {          # Assign each value to $_
    .print;           # print $_;
}

# Same thing, but using an array
my @nums = 1..5;
for @nums {
    .print;
}

# Same, but uses an array that's not a range
my @nums = (1, 2, 3, 4, 5);
for @nums {
    .print;
}

# Using a different variable than $_
for 1..5 -> $var {
    print $var;
}

在上面的所有示例中,for 的陣列引數也可以可選地用括號括起來。特殊的“尖”語法 -> 將在後面的章節中詳細解釋,但值得注意的是,我們可以將其擴充套件為在每次迴圈迭代中從陣列中讀取多個值

my @nums = 0..5;
for @nums -> $even, $odd {
  say "Even: $even Odd: $odd";
}

這將列印以下行

Even: 0 Odd: 1
Even: 2 Odd: 3
Even: 4 Odd: 5

for 也可以用作語句字尾,就像我們對 ifunless 所做的那樣,儘管有一些注意事項

print $_ for (1..5);    # Prints "12345"
print for (1..5);        # Parse Error! Print requires an argument
.print for 1..5;  # Prints "12345"

C 語言程式設計師將認識到 loop 結構的行為,它與 C 語言中的 for 迴圈具有相同的格式和行為。Raku 重新使用了 for 的名稱來表示上一節中看到的陣列迴圈結構,並使用 loop 的名稱來描述 C 語言迴圈的增量行為。以下是 loop 結構

loop (my $i = 0; $i <= 5; $i++) {
    print $i;            # "12345"
}

通常,loop 接受這三個元件

loop ( INITIALIZER ; CONDITION ; INCREMENTER )

loop 中的 INITIALIZER 是一行程式碼,它在迴圈開始之前執行,但具有與迴圈體相同的作用域。CONDITION 是在每次迭代之前檢查的布林測試。如果測試為假,則迴圈退出,如果為真,則迴圈重複。INCREMENTER 是在迴圈結束時發生的一條語句,在下一輪迭代開始之前。所有這些部分都可以選擇性地省略。以下列出了五種編寫相同迴圈的方法

loop (my $i = 0; $i <= 5; $i++) {
    print $i;            # "12345"
}

my $i = 0;    # Small Difference: $i is scoped differently
loop ( ; $i <= 5; $i++) {
    print $i;
}

loop (my $i = 0; $i <= 5; ) {
    print $i;            # "12345"
    $i++;
}

loop (my $i = 0; ; $i++) {
    last unless ($i <= 5);
    print $i;            # "12345"
}

my $i = 0;
loop ( ; ; ) {
    last unless ($i <= 5);
    print $i;            # "12345"
    $i++;
}

如果您想要一個無限迴圈,也可以省略括號,而不是使用 (;;)

my $i = 0;
loop {   # Possibly infinite loop
    last unless ($i <= 5);
    print $i;            # "12345"
    $i++;
}

repeat

[編輯 | 編輯原始碼]

repeat 塊將至少執行一次其主體,因為條件在塊之後。在下面的示例中,您可以看到,即使$i大於2,該塊仍然會執行。

my $i = 3;
repeat {
    say $i;
} while $i < 2;
華夏公益教科書