2016-09-21 3 views
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 или компаньона для класса case ::.

Не мог бы кто-нибудь сказать мне, правильно ли мое предположение? Если нет, то как сопоставляется шаблон для ::, реализованный в Scala?

Спасибо!

EDIT:

Очевидно, что случай класса, как :: есть, ::.unapply будет сгенерирован автоматически для ::. Таким образом, я могу понять, что case x :: y будет соответствовать экземпляру :: (скажем,: :(1, 2)). Но, как мы все знаем, case x :: y также соответствует всем экземплярам типа List, который является базовым классом ::. Таким образом, я думаю, что может быть какая-то особенная unapply были мои предположения правильными.

+2

'::. Unapply' существует, потому что' unapply' автоматически генерируется для классов case, которые '::' есть. –

+0

Спасибо @ m-z, я могу понять, почему 'x :: y' будет соответствовать экземпляру класса' :: 'case. Но я не могу понять, почему он также совпадает с общим «списком», который является базовым классом класса case '::'. –

+0

@mz, пожалуйста, исправьте меня, если я ошибаюсь, я думаю, что автоматически созданный 'D.unapply' соответствует только экземпляру' D', но не базовому классу D. –

ответ

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] 

любой непустой список соответствует случай х :: у. Хотелось бы знать, почему это происходит ?

Непустой список должен быть типа ::. Это то, что он тестирует в шаблоне конструктора. Пустой список, Nil, нет.

+0

Спасибо @ som-snytt. Таким образом, существование класса case не имеет ничего общего с сопоставлением шаблонов для ::, правильно? –

+0

Это шаблон ctor, потому что это класс case. Связанная путаница: https://issues.scala-lang.org/browse/SI-9795 –

+0

Контраст 'scala> (1 :: Nil) соответствует {case List (h) => h}', который является экстрактором (unapplySeq). –

Смежные вопросы