Raku By Example
View me onGitHub
### 模式匹配

my $name = "twostraws";

given $name {
  when "bilbo"      { say "Hello, Bilbo Baggins!"}
  when "twostraws"  { say "Hello, Paul Hudson!"  }
  default           { say "身份验证失败"           }
}



### 同时检查名字和密码

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; # 复合条件


# 带有常量模式的模式匹配
sub describe($x) {
    given $x {
        when 5       { "five" }
        when "hello" { "hi!" }
        when Nil     { "Empty " }
        default      { "something else" }
    }
}

say describe(5);
say describe(Nil);
say describe([1,2,3]);

sub variable_pattern($x) {
  given $x {
    when /Perl6/ { "Camelia" }
    when *       { "Star " ~ "$_" }
    default      {"something else"}
  }
}

say variable_pattern("YoungForPerl6");
say variable_pattern("Star More");
say variable_pattern("Horse");


sub generalSize($x) {
  given $x {
    when Str { .chars }
    when Map { .elems }
    default  { -1 }
  }
}

say generalSize("abc");
say generalSize(Map.new('a', 1, 'b', 2));
say generalSize(pi);

sub patternGuard($x) {
  given $x {
    when Int && ($_ > 0) { "positive" }
    when Int && ($_ < 0) { "negative" }
    default {"something else"}
  }
}

say patternGuard(2);
say patternGuard(-2);
say patternGuard("ha");

sub multiple_alternatives($x) {
  given $x {
    when '0' | '0x' | '0X' { 'multiple_alternatives' }
    default {'something else'}
  }
}

say multiple_alternatives('0x');
say multiple_alternatives('ascii');
say multiple_alternatives('0X');
say multiple_alternatives('0');

my $ch = 23;
given $ch  {
    when Int and * > 10 { say 65}
    when '+' { 1  }
    when '-' { -1 }
    default  { 0  }
}


sub variables_patterns($x) {
  given $x {
    when '+' { 1  }
    when '-' { -1 }
    when *   { $_ }
    default  {say 'something else'}
  }
}

say variables_patterns('+');
say variables_patterns([1,2,3]);
say variables_patterns('variables_patterns');

multi washing_machine(Int \x where * > 10 ) { 65 }
multi washing_machine(Str \x where '+'    ) { 1  }
multi washing_machine(Str \x where '-'    ) { -1 }
multi washing_machine(\x)                   { 0  }

say washing_machine(12);      # 65
say washing_machine(-12);     # 0
say washing_machine('+');     # 1
say washing_machine('-');     # -1
say washing_machine('2333');  # 0
say washing_machine('洗衣机'); # 0


## Object and pattern match
class Address {
    has $.street;
    has $.city;
    has $.country;
}

class Person {
  has $.name;
  has $.age;
  has $.address;
}

my $alice   = Person.new(
                 :name("Alice"),
                 :age(25),
                 :address(
                     Address.new(
                         :street("1 Scala Lane"),
                         :city("Chicago"),
                         :country("USA"))
                    )
            );
my $bob     = Person.new(
                  :name("Bob"),
                  :age(29),
                  :address(
                      Address.new(
                          :street("2 Java Ave."),
                          :city("Miami"),
                          :country("USA"))
                  )
            );
my $charlie = Person.new(
                  :name("Charlie"),
                  :age(32),
                  :address(
                      Address.new(
                          :street("3 Python Ct."),
                          :city("Boston"),
                          :country("USA"))
                  )
            );

for ($alice, $bob, $charlie) {
    when Person.new(:name("Alice"),:age(25), :address(Address.new())) {
      say "Hi Alice!";
    }
    when * eqv Person.new(
                   :name("Bob"),
                   :age(29),
                   :address(
                       Address.new(
                           :street("2 Java Ave."),
                           :city("Miami"),
                           :country("USA"))
                       )
                    )
    {
       say "Hi Bob!"
    }
    when Person {
      say "Who are you, {.age} year-old person named {.name}?";
    }
}


for (1, 2, 2.7, "one", "two", "four") {
  say "int 1" when 1;
  say "other int $_" when Int | Numeric;
  say "string one" when "one";
  say "other string $_" when Str;
  default { say "unexpected" }
}


# 使用签名进行模式匹配

class Body   { has ( $.head, @.arms, @.legs ) }
class Person { has ( $.mom,  $.body, $.age  ) }

my $age = 42;
multi person's-age-and-legs ( Person ( :$age where * > 40, :$body ( :@legs, *% ), *% ) ) { say "$age {+@legs}" }
person's-age-and-legs Person.new(:$age,body => Body.new(:head,:2arms,legs => <left middle right>)); # 42 3



## Scala-like pattern match
my @langs = (
       ("Scala",   "Martin", "Odersky"),
       ("Clojure", "Rich",   "Hickey"),
       ("Lisp",    "John",   "McCarthy")
       );

for @langs -> $l {
    given $l {
        when ("Scala", $, $) { say "Found Scala" };
        when ($, "John", $)  { say "Found John"  };
    }
}


for 1...4 -> $i {
    given $i {
        when $  { say "even: $i" if $i % 2 ==0}
    }
}


for <5 42 43 101 666 1024 2048> -> $value {
    given $value {
        when 0..9      {  say "$_: One digit"}
        when 10..99    {  say "$_: Two digits" ; proceed; }
        when 42        {  say "$_: Response to the question" }
        when /^\d**3$/ {  say "$_: Three digits" }
        default        {  say "$_: More than three digits" }
    }
    say '';
}

my $ch = '-';
my $sign = do given $ch {
  when '+' {1}
  when '-' {-1}
  default {0}
}

say $sign;

my $prefix = '0x';
my $re = do given $prefix {
    when '0' | '0x' | '0X' { 'OK' }
    when '0b' | 'xb' | 'xxb' { 'Fine' }
    default {'opps'}
}

say $re;

my $num = 42.8;
my $r = do given $num {
    when Int {"Int"}
    when Num {"Num"}
    when Rat {"Rat"}
    default {"opps"}
}

say $r;

my $str = "hello-camelia-rakudo-star";
my $res = do given $str {
    when .chars > 10 { "a long string" }
    when .split('-').elems > 3 {"more than three elements"}
    when .contanis('star') {"blink"}
    default {"opps"}
}

say $res;


# if guard
for (1..10).grep: * % 2 == 0 -> $i {say $i}
for (1..10).grep: {3 < $_ < 6 && $_ % 2 == 0}  -> $i { say $i}

# for Comprehension
my \names = ["chris", "ed", "maurice"];
# my @capNames = gather for names -> $e { take $e.uc} 
my @capNames = gather .uc.take for names;

class Person {
    has $.first;
    has $.last;
}

class Dog {
    has $.name;
}

sub eat($x --> Str) {
    given $x {
        # constant patterns
        when 0 {'zero'}
        #when True {'true'}
        when 'hello' {'you said "hello"'}

        # sequence patterns
        when List(0, *, *) {"a three-element list with 0 as the first element"}
        when List(1, @) {"a list beginning with 1, having any number of elements"}

        # tuples
        when (*,*) {"got $^a and $^b"}
        when (*, *, *) {"got $^a, $^b, and $^c"}

        # constructor patterns
        when Person(first=>'Alexander', last => 'Larry') {"found an Alexander"}
        when Dog(name => 'Suka') {"found a dog named Suka"}

        # typed patterns
        when Str {"you gave me this string: $_"}
        when Int {"thanks for the int: $_"}
        when Num {"thanks for the Num: $_"}
        when Array {"an array of int"}
        when Dog {"a dog"}
        when List {"a list"}
        default {"Unknown"}
    }
}