Raku 程式設計/子例程
在程式碼重用方面,最基本的構建塊是子例程。然而,它們並不是工具包中的唯一構建塊:Raku 還支援 *方法* 和 *子方法*,我們將在討論類和物件時進行討論。
子例程使用 `sub` 關鍵字建立,後跟名稱、可選引數列表,最後是一個程式碼塊。
程式碼塊是包含在 `{}` 花括號中的程式碼組。程式碼塊有許多用途,包括將程式碼分開,將多個語句分組在一起以及為變數建立作用域。
子例程使用 `sub` 關鍵字定義。這是一個示例
sub mySubroutine () {
}
圓括號用於定義子例程的形式引數列表。引數就像普通的 `my` 區域性變數,不同之處在於它們在呼叫子例程時用值初始化。子例程可以使用 `return` 關鍵字將結果傳遞迴呼叫者
sub double ($x) {
my $y = $x * 2;
return $y;
}
可選引數在其後有一個 `?`。此外,可選引數可以使用 `=` 給定預設值。必需引數可能在其後有一個 `!`,儘管這是位置引數的預設值。所有必需引數都必須列在所有可選引數之前。
sub foo (
$first, # First parameter, required
$second!, # Second parameter, required
$third?, # Third parameter, optional (defaults to undef)
$fourth = 4 # Fourth parameter, optional (defaults to 4)
)
普通引數按其位置傳遞:第一個傳遞的引數進入第一個位置引數,第二個進入第二個,依此類推。但是,還有一種方法可以透過名稱傳遞引數,並且可以以任何順序傳遞。命名引數基本上是鍵值對,其中一個字串名稱與一個數據值相關聯。可以使用鍵值對或副詞語法傳遞命名資料值。
sub mySub(:name($value), :othername($othervalue))
當然,子例程簽名允許使用一種特殊的簡寫方式,如果你變數與鍵值對的名稱相同,則可以使用它
sub mySub(:name($name), :othername($othername))
sub mySub(:$name, :$othername) # Same!
在子例程宣告中,命名引數必須放在所有必需和可選位置引數之後。命名引數預設情況下被視為可選引數,除非在其後有一個 `!`。實際上,你也可以在必需位置引數之後放一個 `!`,但那是預設設定。
sub mySub(
:$name!, # Required
:$type, # Optional
:$method? # Still optional
)
Raku 還允許使用 `*@` 語法使用所謂的“貪婪”引數。
sub mySub($scalar, @array, *@theRest) {
say "the first argument was: $scalar";
say "the second argument was: " ~ @array;
say "the rest were: " ~ @theRest;
}
`*@` 告訴 Raku 將剩餘的引數展平到一個列表中並存儲在陣列 `@theRest` 中。這是為了允許 perl 接受位置或命名陣列,而不需要引用。
my $first = "scalar";
my @array = 1, 2, 3;
mySub($first, @array, "foo", "bar");
上面的程式碼將輸出三行
- 第一個引數是:標量
- 第二個引數是:1, 2, 3
- 其餘的是:"foo", "bar"
一旦我們定義了一個子例程,我們就可以在以後呼叫它來獲取結果或操作。我們已經看到了內建的 `say` 函式,你可以在其中傳遞字串,並將這些字串列印到控制檯。我們可以使用上面的 `double` 函式來計算各種值
my $x = double(2); # 4
my $y = double(3); # 6
my $z = double(3.5); # 7
我們可以使用 `&` 符號將對子例程的引用儲存在普通標量變數中
my $sub = &double;
my $x = $sub(7) # 14
在這個例子中,你可以看到我們同時向 `double` 子例程傳遞了整數值和浮點值。但是,我們可以使用型別說明符來限制哪些型別的值
sub double (Int $x) { # $x can only be an int!
return $x * 2;
}
my $foo = double(4); # 8
my $bar = double(1.5); # Error!
Raku 允許你編寫多個具有相同名稱的函式,只要它們具有不同的引數簽名並且用 `multi` 關鍵字標記。這被稱為 *多方法排程*,是 Raku 程式設計的一個重要方面。
multi sub double(Int $x) {
my $y = $x * 2;
say "Doubling an Integer $x: $y";
return $x * 2;
}
multi sub double(Num $x) {
my $y = $x * 2;
say "Doubling a Number $x: $y";
return $x * 2;
}
my $foo = double(5); # Doubling an Integer 5: 10
my $bar = double(3.5); # Doubling a Number 3.5: 7
我們不需要像正常情況下那樣命名子例程,而是可以定義一個 *匿名子例程* 並將對它的引用儲存在一個變數中。
my $double = sub ($x) { return $x * 2; };
my $triple = sub ($x) { return $x * 3; };
my $foo = $double(5); # 10
my $bar = $triple(12); # 36
請注意,我們還可以將這些程式碼引用儲存在一個數組中
my @times;
@times[2] = sub ($x) { return $x * 2; };
@times[3] = sub ($x) { return $x * 3; };
my $foo = @times[2](7); # 14
my $bar = @times[3](5); # 15