[英]Scala optional pattern matching
我發現自己經常使用模式匹配,返回一個Option
,其中無匹配大小寫返回None
,例如
x match {
case A(a) => Some(a)
case B(b) => Some(b)
case _ => None
}
我可以想象使用它來簡化這個
object MaybeMatchImplicits {
implicit class MaybeMatcher[A](val underlying: A) extends AnyVal {
@inline
def maybeMatch[B](f: PartialFunction[A, B]): Option[B] = f.lift.apply(underlying)
}
}
這使得
scala> import MaybeMatchImplicits._
import MaybeMatchImplicits._
scala> 5 maybeMatch { case 5 => 'good }
res0: Option[Symbol] = Some('good)
scala> 6 maybeMatch { case 5 => 'good }
res1: Option[Symbol] = None
我想知道這種方法是否隱藏任何陷阱和/或在Scala 2.11+中是否有更簡單/更好/更慣用的機制。
更新:目標是處理匹配的rhs上的任意計算,這使得基於異常的解決方案不合需要。
成語:
scala> case class A(a: Int) ; case class B(b: String)
defined class A
defined class B
scala> def f(x: Any) = Option(x) collect { case A(a) => a ; case B(b) => b }
f: (x: Any)Option[Any]
scala> f(42)
res0: Option[Any] = None
scala> f(A(42))
res1: Option[Any] = Some(42)
scala> f(B("ok"))
res2: Option[Any] = Some(ok)
或者:
scala> import PartialFunction.{cond => when, condOpt => whenever}
import PartialFunction.{cond=>when, condOpt=>whenever}
scala> def f(x: Any) = whenever(x) { case A(a) => a ; case B(b) => b }
f: (x: Any)Option[Any]
scala> f(42)
res3: Option[Any] = None
scala> f(A(42))
res4: Option[Any] = Some(42)
scala> f(B("ok"))
res5: Option[Any] = Some(ok)
使用get
方法(請參閱下面給出的實現),該方法將給定值包裝在選項周圍,然后收集所需的值。
使用選項包裝值,然后收集您想要收集的內容。
Option(x: Any).collect { case 1 => 1 }
要么
x get { case 2 => 2 } // get implementation is given below
Scala REPL
scala> Option(1).collect { case 1 => 1 }
res0: Option[Int] = Some(1)
scala> Option(2).collect { case str: String => "bad" }
<console>:12: error: scrutinee is incompatible with pattern type;
found : String
required: Int
Option(2).collect { case str: String => "bad" }
^
scala> Option(2: Any).collect { case str: String => "bad" }
res2: Option[String] = None
scala> Option(2: Any).collect { case 2 => "bad" }
res3: Option[String] = Some(bad)
implicit class InnerValue[A](value: A) {
def get[B](pf: PartialFunction[Any, B]): Option[B] = Option(value) collect pf
}
Scala REPL
scala> implicit class InnerValue[A](value: A) {
| def get[B](pf: PartialFunction[Any, B]): Option[B] = Option(value) collect pf
| }
defined class InnerValue
scala> 2.get { case 2 => 2}
res5: Option[Int] = Some(2)
scala> 2.get { case 3 => 2}
res6: Option[Int] = None
現在您可以invoke
get方法並傳遞partial函數。 現在,您可能會獲得包含在Some中的值或將獲得None。
請注意,上面的API(get方法)不是類型安全的,您可以這樣做
2.get { case str: String => str }
哪個返回None。
現在,如果您想要類型安全,請進行以下更改
implicit class InnerValue[A](value: A) {
def get[B](pf: PartialFunction[A, B]): Option[B] = Option(value) collect pf
}
請注意,在partial函數中,輸入參數類型是A
而不是Any。
現在,當你這樣做
2.get { case str: String => str }
您將收到編譯錯誤。
scala> 2.get { case str: String => str }
<console>:15: error: scrutinee is incompatible with pattern type;
found : String
required: Int
2.get { case str: String => str }
您可以通過執行以下操作來解決編譯錯誤
scala> (2: Any) get { case str: String => str}
res16: Option[String] = None
我會這樣做:
def trial(a:Any, f:Any => Any) = try Some(f(a)) catch {case _:MatchError => None}
implicit class BetterAny(a:Any) {
def betterMatch(f:Any => Any) = trial(a, f)
}
// some example classes
case class A(i:Int)
case class B(s:String)
在REPL上:
scala> A(1) betterMatch {case A(a) => a; case B(b) => b}
res11: Option[Any] = Some(1)
scala> 2 betterMatch {case A(a) => a; case B(b) => b}
res12: Option[Any] = None
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.