pattern-matching - Rakudo Perl 6 是否有类似 Scala 中的 case Class 的结构?

标签 pattern-matching raku

在 Scala 中,案例类如下所示:

val alice   = Person("Alice",   25, Address("1 Scala Lane", "Chicago", "USA"))
val bob     = Person("Bob",     29, Address("2 Java Ave.",  "Miami",   "USA"))
val charlie = Person("Charlie", 32, Address("3 Python Ct.", "Boston",  "USA"))

for (person <- Seq(alice, bob, charlie)) {
    person match {
        case Person("Alice", 25, Address(_, "Chicago", _) => println("Hi Alice!")
        case Person("Bob",   29, Address("2 Java Ave.", "Miami", "USA")) => println("Hi Bob!")
        case Person(name,   age, _) => println(s"Who are you, $age year-old person named $name?")
    }

我想在 Perl 6 中实现这个,但失败了:

class Address {
    has Str $.street;
    has Str $.city;
    has Str $.country;
}

class Person {
    has Str $.name;
    has Int $.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) -> $s {
  given $s {
    # when Person { say $alice }; # works!
    when Person.new(:name("Alice"),   :age(25), :address(Address.new(:street("1 Scala Lane"), :city("Chicago"), :country("USA")))) {
      say "Hi Alice!"; # doesn't work
    }
    when Person.new(:name("Bob"),     :age(29), :address(Address.new(:street("2 Java Ave."), :city("Miami"), :country("USA")))) {
       say "Hi Bob!" # doesn't work
    }
    when Person.new(:name("Charlie"), :age(32), :address(Address.new(:street("3 Python Ct."), :city("Boston"), :country("USA")))) {
      say "Who are you, $age year-old person named $name?"; # doesn't work
    }
  }
}

Scala 中的模式匹配似乎更强大。但我想知道 Rakudo Perl 6 是否可以实现这一点?

最佳答案

尝试使用* eqvwhen 语句中检查两个对象的结构是否相同。

class Address {
    has Str $.street;
    has Str $.city;
    has Str $.country;
}

class Person {
    has Str $.name;
    has Int $.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 * eqv Person.new(:name("Alice"),:age(25), :address(Address.new(:street("1 Scala Lane"), :city("Chicago"), :country("USA")))) {
        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 循环会自动设置主题(即 $_),因此 given block 是不需要。

最后一个 when block 内的 {.age} 正在访问 $_.age 方法并将其插入到字符串中。

此外,由于对象可以与自身智能匹配,因此使用以下 for 循环可以获得完全相同的结果:

for ($alice, $bob, $charlie) {
    when $alice { say "Hi Alice!"                                          }
    when $bob   { say "Hi Bob!"                                            }
    when Person { say "Who are you, {.age} year-old person named {.name}?" }
}

关于pattern-matching - Rakudo Perl 6 是否有类似 Scala 中的 case Class 的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46041223/

相关文章:

Haskell 字节串 : How to pattern match?

sorting - 快速汉明距离计分

scala - Scala 中的类型边界和模式匹配

raku - 如何控制线程数?

abstract-syntax-tree - 从另一个程序获取 Perl 6 文件的 QAST

perl - 有多少种方法可以描述Perl 6中的斐波那契数列?

raku - 将包转换为 perl6

pattern-matching - `with`语句中Agda不确定是否生成构造函数的情况如何处理?

Scala 的 Stream 删除警告

encoding - Raku:如何读取STDIN原始数据?