390 Stimmen

Wie umgehe ich die Typ-Löschung in Scala? Oder, warum kann ich nicht den Typ-Parameter meiner Sammlungen erhalten?

Es ist eine traurige Tatsache des Lebens auf Scala, dass, wenn Sie eine List[Int] instanziieren, können Sie überprüfen, dass Ihre Instanz eine Liste ist, und Sie können überprüfen, dass jedes einzelne Element davon ein Int ist, aber nicht, dass es eine List[Int] ist, wie leicht überprüft werden kann:

scala> List(1,2,3) match {
     | case l : List[String] => println("A list of strings?!")
     | case _ => println("Ok")
     | }
warning: there were unchecked warnings; re-run with -unchecked for details
A list of strings?!

Mit der Option -unchecked wird die Schuld direkt auf das Löschen des Typs geschoben:

scala>  List(1,2,3) match {
     |  case l : List[String] => println("A list of strings?!")
     |  case _ => println("Ok")
     |  }
<console>:6: warning: non variable type-argument String in type pattern is unchecked since it is eliminated by erasure
        case l : List[String] => println("A list of strings?!")
                 ^
A list of strings?!

Warum ist das so, und wie kann ich das Problem umgehen?

11voto

Jus12 Punkte 17438

Ich habe eine etwas bessere Lösung für diese Einschränkung der ansonsten großartigen Sprache gefunden.

In Scala tritt das Problem der Typenlöschung bei Arrays nicht auf. Ich denke, es ist einfacher, dies anhand eines Beispiels zu demonstrieren.

Nehmen wir an, wir haben eine Liste von (Int, String) gibt es eine Warnung, dass der Typ gelöscht wurde

x match {
  case l:List[(Int, String)] => 
  ...
}

Um dies zu umgehen, erstellen Sie zunächst eine Fallklasse:

case class IntString(i:Int, s:String)

dann in der Musterübereinstimmung etwas tun wie:

x match {
  case a:Array[IntString] => 
  ...
}

was perfekt zu funktionieren scheint.

Dies erfordert geringfügige Änderungen in Ihrem Code, um mit Arrays anstelle von Listen zu arbeiten, sollte aber kein großes Problem darstellen.

Beachten Sie, dass die Verwendung von case a:Array[(Int, String)] immer noch eine Warnung wegen Typenlöschung ausgeben, so dass es notwendig ist, eine neue Containerklasse zu verwenden (in diesem Beispiel, IntString ).

6voto

rained_in Punkte 61

Da Java den tatsächlichen Elementtyp nicht kennt, fand ich es am nützlichsten, einfach die List[_] . Dann verschwindet die Warnung und der Code beschreibt die Realität - es ist eine Liste von etwas Unbekanntem.

4voto

agilesteel Punkte 16640

Ich frage mich, ob dies ein geeigneter Workaround ist:

scala> List(1,2,3) match {
     |    case List(_: String, _*) => println("A list of strings?!")
     |    case _ => println("Ok")
     | }

Er entspricht nicht dem Fall der "leeren Liste", aber er gibt einen Kompilierfehler, keine Warnung!

error: type mismatch;
found:     String
requirerd: Int

Dies hingegen scheint zu funktionieren....

scala> List(1,2,3) match {
     |    case List(_: Int, _*) => println("A list of ints")
     |    case _ => println("Ok")
     | }

Ist das nicht irgendwie noch besser, oder verstehe ich hier etwas nicht?

1voto

matanster Punkte 14503

Das ist keine Lösung, aber eine Möglichkeit, damit zu leben, ohne es ganz unter den Teppich zu kehren: Hinzufügen der @unchecked Bemerkung. Siehe hier - http://www.scala-lang.org/api/current/index.html#scala.unchecked

1voto

Ich wollte eine Antwort hinzufügen, mit der das Problem verallgemeinert wird: Wie erhalte ich eine String-Darstellung des Typs meiner Liste zur Laufzeit?

import scala.reflect.runtime.universe._

def whatListAmI[A : TypeTag](list : List[A]) = {
    if (typeTag[A] == typeTag[java.lang.String]) // note that typeTag[String] does not match due to type alias being a different type
        println("its a String")
    else if (typeTag[A] == typeTag[Int])
        println("its a Int")

    s"A List of ${typeTag[A].tpe.toString}"
}

val listInt = List(1,2,3)
val listString = List("a", "b", "c")

println(whatListAmI(listInt))
println(whatListAmI(listString))

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