2014-02-23 16 views
5

Im Beispiel unten, in der zweiten case würde ich den gleichen Kompilierungsfehler wie in der ersten case erwarten, aber es kompiliert. Warum?Warum kann ich im scala-Match einen unmöglichen Fall haben?

object CaseMatching extends App { 

    case class Id(value: Long) 
    object Id { val zero = Id(0) } 
    case class Name(value: String) 
    case class IdName(id: Id, name: Name) 

    IdName(Id(0), Name("A")) match { 
    case IdName(_, Id(0) ) => // does not compile (as expected) 
    case IdName(_, Id.zero) => // does compile (but should not ?) 
    case IdName(Id.zero, _) => println("OK") // this is OK and will match 
    case _ => 
    } 

} 

Warum ist das relevant? - Ich brauchte den größten Teil einer Stunde, um herauszufinden, warum der folgende Fall nie erfüllt wurde: case TreeEntry(_, Some(child), _, _, NodeType.DIR, _, _) Das war, weil der NodeType im 4. Feld und nicht im 5. Feld ist. Ich hätte es geschätzt, wenn der Compiler es mir gesagt hätte!

Antwort

4

Kürzeste Antwort: machen Name final reicht aus, um den Compiler zu überzeugen, dass zero nicht eins ist. Siehe this issue und Umgebung.

Es würde auf eine Art Test warnen, die ein isInstanceOf ist:

<console>:15: warning: fruitless type test: a value of type CaseMatching.Name cannot also be a CaseMatching.Id 
      case IdName(_, _: Id) => 
          ^

aber nicht, wenn Gleichheit zu testen, da Gleichheit universell ist.

Hier ist ein weiteres gutes, case IdName(_, Id) =>

<console>:15: error: pattern type is incompatible with expected type; 
found : CaseMatching.Id.type 
required: CaseMatching.Name 
Note: if you intended to match against the class, try `case _: Id` 
      case IdName(_, Id) => 
         ^

Was Sie wollen, ist:

scala> IdName(Id(0), Name("A")) match { case IdName(_, id: Id.zero.type) => } 
<console>:21: warning: fruitless type test: a value of type Name cannot also be a Id (the underlying of Id.zero.type) 
       IdName(Id(0), Name("A")) match { case IdName(_, id: Id.zero.type) => } 
                     ^

Die Singleton-Typ enthält nur diesen Wert, so verwendet es eq für den Test; und als Typprüfung warnt es auch. (Es verwendet eq statt equals wie diese Woche.)

nicht sicher, wie weit dies für Dich geht, aber:

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

sealed trait Id { def value: Long } 
case class Nonzero(value: Long) extends Id 
case object Zero extends Id { val value = 0L } 
case class Name(value: String) 
case class IdName(id: Id, name: Name) 

// Exiting paste mode, now interpreting. 

scala> IdName(Zero, Name("A")) match { case IdName(_, Zero) => 1 } 
<console>:14: error: pattern type is incompatible with expected type; 
found : Zero.type 
required: Name 
       IdName(Zero, Name("A")) match { case IdName(_, Zero) => 1 } 
                  ^
+0

Ich habe versucht zu machen Null eine Kompilierung konstant, zum Beispiel 'final val Null = Id (0)' aber es würde immer noch kompilieren. Was ist der Unterschied zwischen diesem Fall und der einfachen Übergabe von "Id (0)"? Können Sie einen Hinweis geben, wie Sie Fehler vermeiden können? – stoyanr

+0

@stoyanr fügte die korrekte Antwort hinzu. –

+0

@stoyanr hat die kürzeste Antwort mit Link zum Problem hinzugefügt. Ihr Kommentar: Id (0) ist keine Konstante, daher ändert Ihre Syntax nichts. –

Verwandte Themen