8 Stimmen

Scala - unapply zu Int hinzufügen

Ich möchte dies tun können:

scala> val Int(i) = "1"
i: Int = 1

Aber Int hat keine unapply Methode.

Ich fand diese Antwort die Anweisungen zum impliziten Hinzufügen einer Methode zu einem bestehenden Objekt enthält, habe ich es ausprobiert. Die dort angegebene Lösung funktioniert, aber leider nicht für den Musterabgleich. Hier ist, was ich habe:

object UnapplyInt {
  val IntRE = """^(\d+)$""".r
  def unapply(v: String): Option[Int] = v match {
    case IntRE(s) => Some(s.toInt)
    case _ => None
  }
}
implicit def int2unapplyInt(objA: Int.type) = UnapplyInt

Diese Testfälle sind alle in Ordnung:

val UnapplyInt(i) = "1"       // pattern matching with unapply is fine
val i = Int.unapply("1").get  // implicit conversion is fine

Aber die, die ich will, scheitert:

scala> val Int(i) = "1"
<console>:10: error: object Int is not a case class constructor, nor does it have an unapply/unapplySeq method
       val Int(i) = "1"
           ^

Wenn die implizite Konvertierung funktioniert und der Mustervergleich mit unapply funktioniert, warum fügt Scala diese beiden Dinge nicht für den impliziten Mustervergleich zusammen?

8voto

Owen Punkte 37648

エディット Meine ursprüngliche Argumentation war also nicht stichhaltig. Der wahre Grund stammt aus Abschnitt 8.1.8 der Scala-Sprachbeschreibung

Syntax:
    SimplePattern ::= StableId ‘(’ [Patterns] ‘)’

Das heißt, das Extraktorobjekt muss stabil sein, und eine implizite Umwandlung ist nicht stabil. Es wird keine Erklärung dafür gegeben, warum der Extraktor stabil sein muss; ich vermute, es liegt daran, dass Scala den Extraktor nicht als eine Ausdruck denn das könnte schnell zweideutig werden:

... match {
    foo(bar)(baz)
}

Welches ist nun der Konstruktor und welches sind die Mustervariablen?

Glücklicherweise kann man das tun, und es funktioniert einwandfrei (obwohl es, wie Sie bemerkten, andere Probleme mit sich bringt):

object Int {
    def unapply(v: String) = try Some(v.toInt)
        catch { case _: NumberFormatException => None }
}

val Int(i) = "5"

da der Typ Int und das Objekt Int befinden sich in verschiedenen Namespaces.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X