如何实现模式匹配?

时间:2016-09-21 03:04:17

标签: scala pattern-matching

例如,

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中如何实现::的模式匹配?

谢谢!

修改

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

1 个答案:

答案 0 :(得分:2)

它被称为构造函数模式:

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

类型(::)必须符合模式类型(List),然后“arg”模式必须匹配。

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

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

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]
  

任何非空List都匹配大小写x :: y。我想知道为什么   这会发生吗?

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