2013-11-03 15 views
16

Dopo aver letto questo post su come utilizzare la corrispondenza del modello su Vector (o qualsiasi raccolta che implementa Seq), ho verificato la corrispondenza del modello su questa raccolta.Pattern Matching "case Nil" per Vector

scala> x // Vector 
res38: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3) 

scala> x match { 
    | case y +: ys => println("y: " + "ys: " + ys) 
    | case Nil => println("empty vector") 
    | } 
<console>:12: error: pattern type is incompatible with expected type; 
found : scala.collection.immutable.Nil.type 
required: scala.collection.immutable.Vector[Int] 
Note: if you intended to match against the class, try `case _: <none>` 
       case Nil => println("empty vector") 
        ^

Ecco dhg 's risposta che spiega +::

object +: { 
    def unapply[T](s: Seq[T]) = 
    s.headOption.map(head => (head, s.tail)) 
} 

REPL mi dimostra che

scala> Vector[Int]() == Nil 
res37: Boolean = true 

... e allora perché non posso usare questa case Nil economico per un Vector?

risposta

24

Il confronto Vector[Int]() == Nil è possibile perché non esiste alcun vincolo sul livello di tipo per ciò che si confronta; che consente l'attuazione di equals per collezioni, d'altra parte, per eseguire un elemento rispetto elemento indipendentemente dal tipo di insieme:

Vector(1, 2, 3) == List(1, 2, 3) // true! 

In pattern matching, non si può avere un caso per un elenco vuoto (Nil) quando il tipo non è correlato alla lista (è un Vector).

È possibile fare questo però:

val x = Vector(1, 2, 3) 

x match { 
    case y +: ys => println("head: " + y + "; tail: " + ys) 
    case IndexedSeq() => println("empty vector") 
} 

ma vorrei suggerire semplicemente di utilizzare il caso di default qui, perché se x non hai un elemento di testa, deve essere tecnicamente vuoto:

x match { 
    case y +: ys => println("head: " + y + "; tail: " + ys) 
    case _ => println("empty vector") 
} 
+0

Grazie per questa risposta. Come follow-up a parte, l'uso di un "catch-all" '_' nell'abbinamento di modelli è in genere una buona o cattiva pratica? Capisco la tua ragione per usare '_' qui da quando, nelle tue parole," Ma ti suggerirei di usare solo il caso predefinito qui, perché se x non ha un elemento head, deve essere tecnicamente vuoto. " –

+2

Catch all può catturare accidentalmente più casi di quanto pensassi. Per i tipi chiaramente elencati (sigillati) suggerirei di non usare '_'. Ad esempio, con 'List' hai il controllo del compilatore:' def foo (xs: List [Any]) = xs match {case head :: tail => "yes"} 'ti dà un avvertimento,' def foo (xs: Vector [Any]) = xs match {case head +: tail => "yes"} 'no. Per 'List' vorrei usare' case Nil', per seq 'caso indicizzato _' ... –