【发布时间】:2021-01-30 22:07:07
【问题描述】:
为什么 Scala 同时拥有unapply 和unapplySeq?两者有什么区别?我什么时候应该更喜欢其中一个?
【问题讨论】:
标签: scala pattern-matching unapply
为什么 Scala 同时拥有unapply 和unapplySeq?两者有什么区别?我什么时候应该更喜欢其中一个?
【问题讨论】:
标签: scala pattern-matching unapply
不再赘述和简化:
对于常规参数apply 构造和unapply 解构:
object S {
def apply(a: A):S = ... // makes a S from an A
def unapply(s: S): Option[A] = ... // retrieve the A from the S
}
val s = S(a)
s match { case S(a) => a }
对于重复的参数,apply 构造和unapplySeq 解构:
object M {
def apply(a: A*): M = ......... // makes a M from an As.
def unapplySeq(m: M): Option[Seq[A]] = ... // retrieve the As from the M
}
val m = M(a1, a2, a3)
m match { case M(a1, a2, a3) => ... }
m match { case M(a, as @ _*) => ... }
请注意,在第二种情况下,重复参数被视为 Seq 以及 A* 和 _* 之间的相似性。
因此,如果您想对自然包含各种单个值的内容进行解构,请使用unapply。如果您想解构包含Seq 的内容,请使用unapplySeq。
【讨论】:
固定数量与可变数量。 Pattern Matching in Scala (pdf) 很好地解释了它,并带有镜像示例。我在this answer 中也有镜像示例。
简单地说:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
scala> List(1,2,3,4) match { case Sorted(xs) => xs }
res0: Seq[Int] = List(1, 2, 3, 4)
scala> List(1,2,3,4) match { case SortedSeq(a, b, c, d) => List(a, b, c, d) }
res1: List[Int] = List(1, 2, 3, 4)
scala> List(1) match { case SortedSeq(a) => a }
res2: Int = 1
那么,您认为下面的例子中体现了哪些?
scala> List(1) match { case List(x) => x }
res3: Int = 1
【讨论】:
List(a,b,c) 上进行匹配就像在 a :: b :: c :: Nil 上进行匹配,但似乎 Scala 并没有这样做;相反,它使用List 的unapplySeq 方法。
一些例子:
scala> val fruit = List("apples", "oranges", "pears")
fruit: List[String] = List(apples, oranges, pears)
scala> val List(a, b, c) = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val List(a, b, _*) = fruit
a: String = apples
b: String = oranges
scala> val List(a, _*) = fruit
a: String = apples
scala> val List(a,rest @ _*) = fruit
a: String = apples
rest: Seq[String] = List(oranges, pears)
scala> val a::b::c::Nil = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val a::b::rest = fruit
a: String = apples
b: String = oranges
rest: List[String] = List(pears)
scala> val a::rest = fruit
a: String = apples
rest: List[String] = List(oranges, pears)
【讨论】: