2016-07-25 1 views
3

Je suis plutôt confus au sujet de ce qui se passe ici:Type de Erasure à Scala

import scala.collection.immutable._ 

object Main extends App { 
    sealed trait Node 

    sealed trait Group 

    case class Sheet(
    val splat: String, 
    val charname: String, 
    val children: ListMap[String, Node], 
    val params0: ListMap[String, Param], //params0 to separate sheet-general parameters 

    val note: Option[Note] 
    ) extends Node with Group 

    case class Attributes(val name: String) extends Node with Group 

    case class Param(val name: String, val value: String) extends Node 
    case class Note(val note: String) extends Node 

J'ai trois versions d'une fonction de remplacement - le dernier est celui que je suis en train d'essayer d'écrire, la d'autres ne font que déboguer.

class SheetUpdater(s: Sheet) {  
    def replace1[T <: Group](g: T): Unit = { 
     s.children.head match { 
     case (_, _:Sheet) => 
     case (_, _:Attributes) => 
     } 
    } 
    } 

Cette version jette aucun avertissement, donc apparemment j'avoir accès au type de s.children lors de l'exécution.

class SheetUpdater(s: Sheet) { 
    def replace2[T <: Group](g: T): Unit = { 
     g match { 
     case _:Sheet => 
     case _:Attributes => 
     } 
    } 
    } 

ne retrouve pas cette version donc apparemment les détails sur le type de g sont également disponibles lors de l'exécution ...

class SheetUpdater(s: Sheet) { 
    def replace3[T <: Group](g: T): Unit = { 
     s.children.head match { 
     case (_, _:T) => //! 
     case (_, _:Attributes) => 
     } 
    } 
    } 

... mais tout de même, cela finit par me jeter l'avertissement redouté Abstract type pattern T is unchecked since it is eliminated by erasure. Que se passe t-il ici?

Répondre

7

Dans Scala, les génériques sont effacés lors de l'exécution, ce qui signifie que les types d'exécution List[Int] et List[Boolean] sont identiques. C'est parce que la JVM dans son ensemble efface les types génériques. Tout ceci est dû au fait que la JVM voulait rester rétrocompatible depuis l'introduction des génériques ...

Il existe un moyen de contourner cela dans Scala en utilisant un ClassTag, qui est un paramètre implicite que l'on peut ensuite enfiler avec quel que soit le générique que vous utilisez.

Vous pouvez penser à : ClassTag en passant le type du générique en tant qu'argument. (Il est du sucre syntaxique pour passer un paramètre implicite de type ClassTag[T].)

import scala.reflect.ClassTag 

class SheetUpdater(s: Sheet) { 
    def replace3[T <: Group : ClassTag](g: T): Unit = { 
    s.children.head match { 
     case (_, _:T) => //! 
     case (_, _:Attributes) => 
    } 
    } 
} 

Newer answers of this question have more details.

+0

Je suppose que ma question est alors "où est mon générique"? Ce n'est pas comme si je correspondais à 'List [T]' ou quelque chose de similaire, alors ... – linkhyrule5

+0

@ linkhyrule5 le générique est 's.children: ListMap [Chaîne, Noeud]'. – Alec

+0

Bien sûr, mais je me suis décomposé - je fais correspondre les enfants, qui devraient toujours être bien typés. – linkhyrule5