2016-10-24 4 views
3

Ich habe den folgenden Code Wert auf die Art der Standard würfenScala gegossen auf eine Variable Typ

def fct[T](value: Any, default: T): T = { 
    val result = value.asInstanceOf[T] 
    println(result, result.getClass.getName, result.isInstanceOf[T]) 
    result 
} 

val res = fct("foo", 42) 

Welches Ergebnis ist:

(foo,java.lang.String,true) 
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
    at scala.runtime.BoxesRunTime.unboxToInt(Test.sc2.tmp) 
    at #worksheet#.res$lzycompute(Test.sc2.tmp:7) 
    at #worksheet#.res(Test.sc2.tmp:7) 
    at #worksheet#.#worksheet#(Test.sc2.tmp:7) 

Frage ist: warum die PrintIn wird angezeigt? Die Besetzung sollte fehlschlagen. Ich habe versucht, die 3 Zeilen zu versuchen, aber keine Ausnahme wird während des Funktionsaufrufs ausgelöst.

+1

Das ist komisch. Beachten Sie, dass ich ein Ergebnis von '(Some (foo), scala.Some, true)' aus Ihrem Code erhalte. – Yawar

+0

Ja sorry, ich korrigiere das – Benjamin

+0

Das ist in der Tat seltsam. Und ich bekomme '(foo, java.lang.String, true)' auf der Scala 2.11.8 Konsole. Der Funktionskörper wird irgendwie träge ausgeführt. Was ist seltsam. –

Antwort

7

Wegen Typ Löschung, dann ist es unmöglich, tatsächlichvalue.{as/is}InstanceOf[T] implementieren, wo T ein Typparameter ist. Scala's Designer entschieden, dass es noch kompilieren sollte, aber value.asInstanceOf[T] ist eigentlich ein No-Op (genau wie das Äquivalent (T) value in Java), während value.isInstanceOf[T] immer true zurückgibt (in Java ist value instanceOf T ein Compilerfehler). (Da es nie tut, was Sie wollen, würde Ich mag zu stark eine Warnung statt sehen, zumindest für isInstanceOf.)

Aber Scala erlaubt zu tun, was Sie ClassTag mit wollen:

import scala.reflect.ClassTag 

def fct[T](value: Any, default: T)(implicit tag: ClassTag[T]): T = { 
    val result = (tag match { 
     case ClassTag.Int => value.asInstanceOf[Int] 
     ... same for other primitives 
     case _ => tag.runtimeClass.cast(value) 
    }).asInstanceOf[T] 
    println(result, result.getClass.getName, tag.runtimeClass.isInstance(result)) 
    result 
} 

(Sie noch müssen asInstanceOf[T] weil tag.runtimeClassin der Regel die gleiche Klasse gibt T stellt aber nicht immer, so sein statischer Rückgabetyp hat Class[_] und cast kehrt Any) zu sein.

jedoch Mustervergleich : T Griffe Vorhandensein eines ClassTag automatisch und bereits behandelt Boxen, so

def fct[T](value: Any, default: T)(implicit tag: ClassTag[T]): T = value match { 
    case result: T => result 
    case _ => default // or whatever you want to do if value is not a T 
} 

ist der bessere Weg, dies zu tun.

+2

Dies wird Erleuchtung genannt. –

+2

Verdammt, ich möchte Sie sein, wenn ich aufwachsen – Yawar

+0

Es kompiliert nicht: Fehler: (6, 4) Typ Mismatch; gefunden: result.type (mit zugrunde liegenden Typ Any) erforderlich: T Ergebnis ^ – Benjamin