Quelles sont les différences entre asInstanceOf et (o: T) dans Scala?

J’ai vu qu’il y a deux méthodes pour lancer un object dans Scala:

foo.asInstanceOf[Bar] (foo: Bar) 

Lorsque j’ai essayé, j’ai trouvé que asInstanceOf n’utilisait pas de conversion implicite alors que l’autre le asInstanceOf .

Quelles sont les différences de comportement entre ces deux méthodes? Et où est-il recommandé d’utiliser l’un sur l’autre?

  • foo.asInstanceOf[Bar] est un type cast , qui est principalement une opération d’exécution. Il dit que le compilateur devrait être forcé de croire que foo est une Bar . Cela peut entraîner une erreur (une ClassCastException ) si et quand foo est évalué comme autre chose qu’une Bar à l’exécution.

  • foo:Bar est une atsortingbution de type, qui est entièrement une opération de compilation. Cela aide le compilateur à comprendre la signification de votre code, sans le forcer à croire tout ce qui pourrait être faux. aucune défaillance d’exécution ne peut résulter de l’utilisation des descriptions de type.

Les descriptions de type peuvent également être utilisées pour déclencher des conversions implicites. Par exemple, vous pouvez définir la conversion implicite suivante:

 implicit def foo(s:Ssortingng):Int = s.length 

puis assurez-vous de l’utiliser comme suit:

 scala> "hi":Int res29: Int = 2 

Atsortingbuer le type Int à une Ssortingng serait normalement une erreur de type à la compilation, mais avant d’abandonner le compilateur recherchera les conversions implicites disponibles pour résoudre le problème. La conversion implicite particulière qui sera utilisée dans un contexte donné est connue à la compilation.

Inutile de dire que les erreurs d’exécution ne sont pas souhaitables. Dans la mesure où vous pouvez spécifier des choses de manière sûre (sans utiliser asInstanceof ), mieux c’est! Si vous utilisez asInstanceOf , vous devriez probablement utiliser match place.

La réponse de Pelotom couvre la théorie plutôt sympathique, voici quelques exemples pour la rendre plus claire:

 def foo(x: Any) { println("any") } def foo(x: Ssortingng) { println("ssortingng") } def main(args: Array[Ssortingng]) { val a: Any = new Object val s = "ssortingng" foo(a) // any foo(s) // ssortingng foo(s: Any) // any foo(a.asInstanceOf[Ssortingng]) // comstacks, but ClassCastException during runtime foo(a: Ssortingng) // does not comstack, type mismatch } 

Comme vous pouvez le voir, l’indication de type peut être utilisée pour résoudre les ambiguïtés. Parfois, ils peuvent être résolus par le compilateur (voir plus loin), qui signalera une erreur et vous devrez la résoudre. Dans d’autres cas (comme dans l’exemple), il utilise simplement la “mauvaise” méthode, pas celle que vous voulez. foo(a: Ssortingng) ne comstack pas, ce qui montre que l’atsortingbution de type n’est pas une dissortingbution. Comparez-le avec la ligne précédente, où le compilateur est content, mais vous obtenez une exception, l’erreur est alors détectée avec le type ascription.

Vous obtiendrez une ambiguïté insoluble si vous ajoutez également une méthode

 def foo(xs: Any*) { println("vararg") } 

Dans ce cas, la première et la troisième invocation de foo ne seront pas compilées, car le compilateur ne peut pas décider si vous voulez appeler le foo avec un seul paramètre Any, ou avec les varargs, car les deux semblent être également bons => vous doit utiliser une atsortingbution de type pour aider le compilateur.

Edit see also Quel est le but de la saisie de type dans Scala?

La programmation en Scala aborde cette question en détail dans le chapitre 15 – Classes de cas et correspondance de modèles .

Fondamentalement, la deuxième forme peut être utilisée comme “Motif typé” dans une correspondance de modèle, en donnant la fonctionnalité isInstanceOf et asInstanceOf . Comparer

 if (x.isInstanceOf[Ssortingng]) { val s = x.asInstanceOf[Ssortingng] s.length } else ... 

contre.

 def checkFoo(x: Any) = x match { case s: Ssortingng => s.length case m: Int => m case _ => 0 } 

Les auteurs suggèrent que la verbosité de la isInstance* est intentionnelle pour vous pousser dans le style de correspondance de motif.

Je ne suis pas sûr quel modèle est le plus efficace pour un type simple sans test cependant.

Il y a un exemple de la différence:

  1. Type cast (asInstanceOf) est une opération d’exécution avec une exception d’exécution possible.
  2. La description est simplement une conversion effectuée au moment de la compilation.

Exemple:

 class Parent() { def method() {} } class Child1 extends Parent() { def method1() {} } class Child2 extends Parent() { def method2() {} } // we return Parent type def getChild1() : Parent = new Child1() def getChild2() : Parent = new Child2() def getChild() : Child1 = new Child1() (getChild1().asInstanceOf[Child1]).method1() // OK (getChild1().asInstanceOf[Child2]).method2() // runtime ClassCastException (getChild1() : Child2).method2() // comstack-time error (getChild2() : Child2).method2() // comstack-time error (getChild() : Parent).method1() // comstack-time error (getChild()).method() // OK // with asInstanceOf, we can cast to anything without comstack-time error getChild1().asInstanceOf[Ssortingng] // runtime ClassCastException getChild1().asInstanceOf[Int] // runtime ClassCastException 

Nous pouvons également appeler la méthode à l’aide de la répartition multiple:

 def prt(p: Parent) = println("parent") def prt(ch: Child1) = println("child") prt(new Parent()) // prints "parent" prt((new Child1()) : Parent) // prints "parent" prt(new Child1()) // prints "child" prt(new Parent().asInstanceOf[Child1]) // runtime ClassCastException prt(new Child1().asInstanceOf[Parent]) // prints "parent" 

Nous pouvons définir une conversion implicite:

 // after definition of implicit conversions implicit def toChild1(p: Parent) : Child1 = new Child1() implicit def toChild2(p: Parent) : Child2 = new Child2() (getChild1() : Child2).method2() // OK - implicit conversion to Child2 in ascription (getChild2() : Child2).method2() // OK - implicit conversion to Child2 in ascription (getChild2()).method1() // OK - implicit conversion to Child1 when calling method1() (getChild2()).method2() // OK - implicit conversion to Child2 when calling method2() (getChild2() : Parent).method() // OK - no implicit conversion (getChild() : Parent).method1() // OK - implicit conversion to Child1 when calling method() getChild1().asInstanceOf[Int] // still runtime ClassCastException (no implicit conversion)