【问题标题】:What is the difference between unapply and unapplySeq?unapply 和 unapplySeq 有什么区别?
【发布时间】:2021-01-30 22:07:07
【问题描述】:

为什么 Scala 同时拥有unapplyunapplySeq?两者有什么区别?我什么时候应该更喜欢其中一个?

【问题讨论】:

    标签: scala pattern-matching unapply


    【解决方案1】:

    不再赘述和简化:

    对于常规参数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

    【讨论】:

      【解决方案2】:

      固定数量与可变数量。 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
      

      【讨论】:

      • 啊,谢谢!这就说得通了。从 Haskell 的角度来看,我认为在 List(a,b,c) 上进行匹配就像在 a :: b :: c :: Nil 上进行匹配,但似乎 Scala 并没有这样做;相反,它使用ListunapplySeq 方法。
      • 这个答案中提到的论文可以在这里找到:michaelrueegg.name/static/papers/PatternMatchingInScala.pdf
      • @dan Scala 可以通过在 :: 伴生对象上使用 unapply 方法,以您期望的方式匹配列表。正如预期的那样,这 unapply 只是将 List(或者更确切地说是 ::)解构为头部和尾部。请注意,这仅适用于列表,不适用于任何 Seq。
      • 以上论文的 URL 似乎已损坏。似乎现在可以在http://wiki.ifs.hsr.ch/SemProgAnTr/files/PatternMatchingInScala.pdf 找到它
      【解决方案3】:

      一些例子:

      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)
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-02
        • 2011-12-12
        • 2010-09-16
        • 2012-03-14
        • 2012-02-06
        • 2011-02-25
        相关资源
        最近更新 更多