2015-12-22 5 views
5

ich einen Fall, Klassenhierarchie haben einige Anfrage und Verarbeitungsfehler zu codieren:Scala Mustererkennung ist auf verschachtelte Fall Klassen keinen Anspruch auf Vollständigkeit

sealed trait OpError 
    sealed trait RequestErrorType 
    sealed trait ProcessingErrorType 

    final case class InvalidEndpoint(reason: String) extends RequestErrorType 
    final case class InvalidParameters(reason: String) extends RequestErrorType 

    final case class InvalidFormat(response: String) extends ProcessingErrorType 
    final case class EntityNotFound(id: Long) extends ProcessingErrorType 

    final case class RequestError(errorType: RequestErrorType) extends OpError 
    final case class ProcessingError(errorType: ProcessingErrorType) extends OpError 

Wenn ich ein einfaches Spiel für alle Muster schreiben:

def printMatches(error: OpError): Unit = error match { 
    case RequestError(InvalidEndpoint(reason)) => //print something 
    case RequestError(InvalidParameters(reason)) => //print something 
    case ProcessingError(InvalidFormat(format)) => //print something 
    case ProcessingError(EntityNotFound(entityId)) => //print something 
    } 

die Compiler gibt mir eine Warnung über fehlendes Spiel:

match may not be exhaustive. 
It would fail on the following input: ProcessingError(_) 
def printMatches(error: OpError): Unit = error match { 

Aber ProcessingError nimmt in einem P rocessingErrorType mit nur zwei Erweiterungen: InvalidFormat und EntityNotFound, die beide in der Musterübereinstimmung berücksichtigt werden. Was vermisse ich?

Noch neugierig ist, dass wenn ich den Parametertyp von InvalidParameters oder InvalidEndpoint in einen String * ändern, ich habe nicht den Fehler:

final case class InvalidParameters(reason: String*) extends RequestErrorType 

Irgendwelche Ideen?

+0

'printMatches (ProcessingError (new ProcessingErrorType {}))' es ist keine Übereinstimmung –

+0

dieses Beispiel verstößt gegen den 'versiegelten' Vertrag. – pedrofurla

+0

In Bezug auf das seltsame Verhalten mit dem String * -Parameter, es klingt wie Scala Umdrehungen der erschöpfenden Prüfung, wenn eine Fallklasse einen varargs Parameter hat: https://issues.scala-lang.org/browse/SI-8178?jql = labels% 20% 3D% 20exhaustivity – ssanj

Antwort

4

Dies ist ein bestätigter Fehler. I filed a bug report for this und es wurde seit Scala 2.12.0-M4 behoben.

+0

Siehe diesen Kommentar für eine Workaround: https://issues.scala-lang.org/browse/SI-9630?focusedCommentId=73864&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment- 73864 – ssanj

0

Sie den Compiler mit einer ungeprüften Anmerkung helfen kann:

... = (error: @unchecked) match ... 

aber Sie sollten sicher sein, Ihr Spiel vollständig.

+0

true, aber ich wollte, dass der Compiler mir hilft, ungültige Instanzen herauszufinden, nicht umgekehrt. ;) – ssanj

0

Ich denke, Vollständigkeitsanpassung funktioniert auf einer einzigen Vererbungsebene. RequestErrorType und ProcessingErrorType sind Teil des Konstruktors, wo diese Vollständigkeit nicht überprüft wird.

Sie können es aus dem Lesen des Codes sehen, aber es scheint, dass Compiler nicht.

+0

Sagen wir die Übereinstimmung von RequestError (InvalidParameters (Grund)) aus printMatches aus, dann sagt mir der Compiler, dass mir genau diese Variation fehlt: "Die Übereinstimmung ist möglicherweise nicht erschöpfend. Sie würde bei der folgenden Eingabe fehlschlagen: RequestError (Ungültige Parameter(_))". Also ich denke, der Compiler kann einige verschachtelte Vererbung herausfinden. – ssanj

1

Sehr interessant! Leider habe ich keine Antwort gefunden. Ich habe um http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#constructor-patterns gedreht, aber ich habe nicht wirklich eine gültige Erklärung für das, was vor sich geht, gefunden.

Hier ist ein einfacher Demo (hoffen, dass Sie nichts dagegen haben):

sealed abstract class ClassOne 
case class ClassOneImpl() extends ClassOne 

sealed abstract class ClassTwo() 
case class ClassTwoImpl() extends ClassTwo 

sealed abstract class Foo 
case class FooOne(x: ClassOne) extends Foo 
case class FooTwo(x: ClassTwo) extends Foo 

def printMatches(st: Foo): Unit = st match { 
    case FooOne(ClassOneImpl()) => println() 
    case FooTwo(ClassTwoImpl()) => println() 
} 

Ich habe beobachtet, dass jede der beiden folgenden Änderungen entfernt die Warnung:
1) Ändern FooOne und FooTwo Signaturen, so dass anstelle des Nehmens ClassOneClassTwo und sie nehmen ClassOneImpl und ClassTwoImpl
2) Entfernen FooOne oder FooTwo so dass es nur einen Fall Klasse verlauf Foo (die t führt o nur ein Fall im Mustervergleich).

Vielleicht könnten wir ein Problem einreichen und sehen, was sie sagen?

+1

Ich habe es als Bug https://issues.scala-lang.org/browse/SI-9630 abgelegt und es wurde seither repariert und geschlossen! Yay! :) – ssanj