TL;DR 我已经写了另一个答案,专注于使用 when
。而这个答案则专注于使用与Signature
相结合的替代方法,Raku强大的模式匹配构造,以及where
从句。
"Raku中的模式匹配是否有保护从句?"
根据我所知道的Scala很少的一些东西,一些(或者大多数)Scala的模式匹配实际上对应于使用Raku签名。(在这种情况下,防卫从句通常是where
从句。)
引用Scala的创造者Martin Odersky在The Point of Pattern Matching in Scala中的话:
instead of just matching numbers, which is what switch statements do, you match what are essentially the creation forms of objects
Raku signatures覆盖了几种用例(耶,双关语)。这些包括Raku中等价于函数式编程典型用例,其中匹配值或函数类型签名(与Haskell类似),以及面向对象编程典型用例,其中匹配嵌套数据/对象并提取所需位(与Scala类似)。
考虑以下Raku代码:
class body { has ( $.head, @.arms, @.legs ) }
class person { has ( $.mom, $.body, $.age ) }
multi person's-age-and-legs # Declare a function that matches ...
( person # ... a person ...
( :$age where * > 40, # ... whose age is over 40 ...
:$body ( :@legs, *% ), # ... noting their body's legs ...
*% ) )
{ say "$age {+@legs}" }
my $age = 42;
person's-age-and-legs # Call function declared above ...
person # ... passing a person.
.new: # Explicitly construct ...
:$age, # ... a middle aged ...
body => body.new:
:head,
:2arms,
legs => <left middle right> # ... three legged person.
# Displays "42 3"
上述代码中有一个类似于 Scala 模式匹配守卫子句的紧密等效位置 -- where * > 40
。(这可以很好地捆绑到subset
类型中。)
我们可以定义其他的multi
,对应不同的情况,例如,如果某人母亲的姓名与特定的正则表达式匹配,可能会提取出该人腿的“名称”(“left”,“middle”等)-- 希望您能理解。
一个不需要拆分人物的默认情况(multi
)可以是:
multi person's-age-and-legs (|otherwise)
{ say "let's not deconstruct this person" }
(在上面的示例中,我们在签名中使用|
前缀来捕获传递给多元函数的所有剩余结构/参数。鉴于我们对已捕获的结构/数据没有任何处理,我们也可以只编写(|)
。)
不幸的是,我认为官方文档中没有提到签名解构。有人可以撰写一本关于Raku签名的书(确实如此,这当然是撰写东西的好方式--甚至是唯一的方式。揭示Raku签名强大力量的我最喜欢的文章是Moritz于2013年撰写的Pattern Matching and Unpacking。Moritz曾经撰写过Raku的书。希望如此。)
Scala的match/case
和Raku的given/when
似乎更简单
确实。
正如@jjmerelo在评论中指出的那样,使用签名意味着每种情况都会有一个multi foo (...) { ...}
,这在语法上比case ... => ...
要复杂得多。
缓解措施:
case _: Int if 10 < ch => 65
会做什么? - Christopher Bottomswhen $_~~Int and $_>10 {…}
。请注意,given
会在块内将值放入$_
中。 - Brad Gilbertif 10 < ch < 120
。 - chenyf$ch
的值设置为9
时,我得到了错误的答案:代码返回65
,而答案应该是0
。然而,when (Int & (* > 10)) { say 65 } ;
这一行似乎可以纠正错误。 - jubilatious1