Raku 中的 given/when 模式匹配
— 焉知非鱼Given When Pattern Match in Raku
模式匹配 #
匹配单个字符串:
my $name = "twostraws";
given $name {
when "bilbo" { say "Hello, Bilbo Baggins!"}
when "twostraws" { say "Hello, Paul Hudson!" }
default { say "身份验证失败" }
}
匹配元组:
my $bool1 = 1;
my $bool2 = 0;
given ($bool1, $bool2) {
when (0, 0) {say "0, 0"}
when (0, 1) {say "0, 1"}
when (1, 0) {say "1, 0"}
when (1, 1) {say "1, 1"}
}
given ("15", "example", "3.14") {
say $_.WHAT;
when ($, $, Str) { say "I got a String of $_[2]" }
}
given (4, 5) {
when ( $, $) {say "Ok"}
}
given ("fly.mp3", 34, "It's funny") {
when (/.mp3$/, /4$/, *.chars > 4) { say "Perfact" }
}
given 5 {
when 1..10 { say "1..10 contains 5" }
}
同时检查名字和密码 #
my $name = "twostraws";
my $password = "fr0st1es";
given ($name, $password) {
when ("bilbo", "bagg1n5") { say "Hello, Bilbo Baggins!" }
when ("twostraws", "fr0st1es") { say "Hello, Paul Hudson!" }
default { say "你是谁?" }
}
使用单个元组 #
my $authentication = ("twostraws", "fr0st1es");
given $authentication {
when ("bilbo", "bagg1n5") { say "Hello, Bilbo Baggins!" }
when ("twostraws", "fr0st1es") { say "Hello, Paul Hudson!" }
default { say "你是谁?" }
}
部分匹配 #
# 你只关心某些感兴趣的值,不关心其它值,使用 `*` 号或 `$` 来代表 "any value is fine"
my $authentication = ("twostraws", "fr0st1es", "127.0.0.1");
given $authentication {
when ("bilbo", "bagg1n5", *) { say "Hello, Bilbo Baggins!"}
when ("twostraws", "fr0st1es", $) { say "Hello, Paul Hudson!" }
default { say "Who are you?" }
}
只匹配元组的一部分 #
# 但仍然想知道其它部分是什么
my $authentication = ("twostraws", "fr0st1es");
given $authentication {
when ("bilbo", *) { say "Hello, Bilbo Baggins!" }
when ("twostraws", *) { say "Hello, Paul Hudson: your password was $_!" }
default { say "Who are you?" }
}
匹配计算型元组 #
sub fizzbuzz(Int $number) returns Str {
given ($number % 3 == 0, $number % 5 == 0) {
when (True, False) { return "Fizz" }
when (False, True) { return "Buzz" }
when (True, True) { return "FizzBuzz" }
when (False, False) { return $number.Str}
}
}
say fizzbuzz(15);
遍历元组 #
my $twostraws = ("twostraws", "fr0st1es");
my $bilbo = ("bilbo", "bagg1n5");
my $taylor = ("taylor", "fr0st1es");
my @users = $twostraws, $bilbo, $taylor;
for @users -> $user {
say $user[0];
}
使用 when 匹配元组中的指定值 #
my $twostraws = ("twostraws", "fr0st1es");
my $bilbo = ("bilbo", "bagg1n5");
my $taylor = ("taylor", "fr0st1es");
my @users = $twostraws, $bilbo, $taylor;
say "User twostraws has the password fr0st1es" when ("twostraws", "fr0st1es") for @users;
# 打印秘密为指定值的用户
say "User $_[0] has password \"fr0st1es\"" when (*, "fr0st1es") for @users;
匹配范围 #
my $age = 36;
given $age {
when 0 ..^ 18 { say "你有活力有时间,但是没钱" }
when 18 ..^ 70 { say "你有活力有钱,但是没时间" }
default { say "你有时间和金钱,但是没活力"}
}
when 可以配合智能匹配操作符 ~~ 单独使用 #
my $age = 36;
when $age ~~ 0 ..^ 18 { say "你有活力有时间,但是没钱" }
when $age ~~ 18 ..^ 70 { say "你有活力有钱,但是没时间" }
default { say "你有时间和金钱,但是没活力"}
使用 contains 方法 #
my $age = 36;
when (0 ..^ 18).contains($age) { say "你有活力有时间,但是没钱" }
when (18 ..^ 70).contains($age) { say "你有活力有钱,但是没时间" }
default { say "你有时间和金钱,但是没活力"}
匹配元组中的范围 #
my $user = ("twostraws", "fr0st1es", 36);
given $user {
my $name = $user[0];
when ($name, *, 0 ..^ 18) { say "$name 有活力有时间,但是没钱" }
when ($name, *, 18 ..^ 70) { say "$name 有活力有钱,但是没时间" }
when ($name, *, *) { say "$name 有时间和金钱,但是没活力" }
}
枚举 #
enum WeatherType <Cloudy Sunny Windy>;
my $today = WeatherType::Cloudy;
given $today {
when WeatherType::Cloudy { say "多云" }
when WeatherType::Sunny { say "晴天" }
when WeatherType::Windy { say "有风" }
}
# 使用 if 语句
if $today ~~ WeatherType::Cloudy { say "多云" }
关联值 #
enum WeatherType (
Cloudy => 100,
Sunny => 50,
Windy => 30
);
my $today = WeatherType::Windy;
given $today {
when WeatherType::Cloudy { say 20*Cloudy }
when WeatherType::Sunny { say 10*Sunny }
when WeatherType::Windy { say 12*Windy }
}
when 从句 #
my @numbers = 1..10;
.say when $_ % 2 == 1 for @numbers;
my @celebrities = "Michael Jackson", "Taylor Swift", "MichaelCaine", "Adele Adkins", "Michael Jordan";
.say when /^Michael/ for @celebrities; # 使用正则表达式
.say when $_.chars > 12 for @celebrities; # 调用方法
.say when /^Michael/ and $_.chars >12 for @celebrities; # 复合条件
proceed #
given-when 有两个小的改变, 并且这俩改变都是开启新行为的, 而不是限制已存在的行为。
第一个小的改变: when 的开关行为不仅仅是用于 given 块儿中的, 而是可以用在任何"主题化"的块儿中的, 例如 for 循环中或接收 $_
作为参数的子例程中。
given $answer {
when "Atlantis" { say "那是对的" }
default { say "BZZZZZZZZZZZZZ!" }
}
for 1..100 {
when * %% 15 { say "Fizzbuzz" }
when * %% 3 { say "Fizz" }
when * %% 5 { say "Buzz" }
default { say $_ }
}
sub expand($_) {
when "R" { say "红警" }
when "G" { say "绿警" }
when "B" { say "蓝警" }
default { say $_ }
}
但是甚至不接受 $_
作为参数的子例程也得到了它们自己的词法变量 $_
供修改。所以规则就是"现在, 在 $_
中有某些我能启动的好东西吗"。如果我们想要, 我们甚至能自己设置 $_
。
sub seek-the-answer() {
$_ = (^100).pick;
when 42 { say "The answer" }
default { say "A number" }
}
换句话说, 我们已经知道了 when 和 given 是单独的。Switch 语句逻辑都在 when 语句中。
第二个小改变: 你可以嵌套 when 语句!
我很确信你没有在野外见过这种用法。但它有时候特别有用:
when * > 2 {
when 4 { say 'Four!' }
default { say 'huge' }
}
default {
say 'little'
}
你可能记得, 在 when 块儿中有一个隐式的 succeed 语句在末尾, 这让周围的主题化块退出。(意思是你不必记着手动退出 switch 语句)。如果你想重写 succeed 语句并继续通过 when block, 那么你在 when block 的末尾写上一个显式的 proceed 即可。
given $verse-number {
when * >= 12 { say "Twelve drummers drumming"; proceed }
when * >= 11 { say "Eleven pipers piping"; proceed }
# ...
when * >= 5 { say "FIIIIIIVE GOLDEN RINGS!"; proceed }
when * >= 4 { say "Four calling birds"; proceed }
when * >= 3 { say "Three French hens"; proceed }
when * >= 2 {
say "Two turtle doves";
say "and a partridge in a pear tree";
}
say "a partridge in a pear tree";
}