首页 文章

如何实现模式匹配?

提问于
浏览
2

例如,

List(1, 2, 3) match {
  case x :: y => (x, y)
}

在上面的代码中,模式匹配将自动发现任何非空 List 与案例 x :: y 匹配 . 我想知道,为什么会这样?

众所周知, List 类中有一个 :: 方法 . 另外,我发现在"list.scala"中有一个 :: 案例类:

/** A non empty list characterized by a head and a tail.
 *  @param head the first element of the list
 *  @param tl   the list containing the remaining elements of this list after the first one.
 *  @tparam B   the type of the list elements.
 *  @author  Martin Odersky
 *  @version 1.0, 15/07/2003
 *  @since   2.8
 */
@SerialVersionUID(509929039250432923L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
  override def tail : List[B] = tl
  override def isEmpty: Boolean = false
}

因此,我们可以编写 ::(1, Nil) 来构造一个新的 List . 更重要的是,使用Scala中的中缀符号,我们能够等效地编写 1 :: Nil (虽然事实证明 Nil.::(1) 将被调用而不是 ::(1, Nil) ,可能是由于某些优先规则 . )

因此,我猜案例类 :::: 的模式匹配有关(例如,模式 x :: y 将匹配 ::.unapply 之类的东西) . 但我没有为案例类 :: 找到任何 unapply 方法或伴随对象 .

谁能告诉我我的猜测是否正确?如果没有,在Scala中如何实现 :: 的模式匹配?

谢谢!

EDIT:

显然,case类为 ::::.unapply 将自动为 :: 生成 . 因此,我可以理解 case x :: y 将匹配 :: 的实例(例如:::(1,2)) . 但众所周知, case x :: y 也匹配 List 类型的所有实例,这是 :: 的基类 . 因此,我认为可能有一些特殊的 unapply 是我猜的正确 .

1 回答

  • 2

    它被称为构造函数模式:

    http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#constructor-patterns

    类型( :: )只需符合模式类型( List ),然后"arg"模式必须匹配 .

    它看起来类似于提取器模式,但是不同 .

    编辑显示外观ma,没有提取器:

    scala> val vs = List(1,2,3)
    vs: List[Int] = List(1, 2, 3)
    
    scala> vs match { case 1 :: rest => "ok" }
    <console>:13: warning: match may not be exhaustive.
    It would fail on the following inputs: List((x: Int forSome x not in 1)), Nil
           vs match { case 1 :: rest => "ok" }
           ^
    res0: String = ok
    
    scala> :javap -pv -
    [snip]
    
      public $line4.$read$$iw$$iw$();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=4, locals=5, args_size=1
             0: aload_0
             1: invokespecial #30                 // Method java/lang/Object."<init>":()V
             4: aload_0
             5: putstatic     #32                 // Field MODULE$:L$line4/$read$$iw$$iw$;
             8: aload_0
             9: getstatic     #35                 // Field $line3/$read$$iw$$iw$.MODULE$:L$line3/$read$$iw$$iw$;
            12: invokevirtual #39                 // Method $line3/$read$$iw$$iw$.vs:()Lscala/collection/immutable/List;
            15: astore_2
            16: aload_2
            17: instanceof    #41                 // class scala/collection/immutable/$colon$colon
            20: ifeq          52
            23: aload_2
            24: checkcast     #41                 // class scala/collection/immutable/$colon$colon
            27: astore_3
            28: aload_3
            29: invokevirtual #45                 // Method scala/collection/immutable/$colon$colon.head:()Ljava/lang/Object;
            32: invokestatic  #51                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
            35: istore        4
            37: iconst_1
            38: iload         4
            40: if_icmpne     49
            43: ldc           #53                 // String ok
            45: astore_1
            46: goto          64
            49: goto          55
            52: goto          55
            55: new           #55                 // class scala/MatchError
            58: dup
            59: aload_2
            60: invokespecial #58                 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
            63: athrow
            64: aload_1
            65: putfield      #28                 // Field res0:Ljava/lang/String;
            68: return
    [snip]
    

    任何非空列表都匹配大小写x :: y . 我想知道,为什么会这样?

    非空List必须是 :: 类型 . 这就是它在构造函数模式中测试的内容 . 空列表 Nil 不是 .

相关问题