2016-07-25 1 views
0

Je veux coder un constructeur de type simple dans scala. Quoi qu'il en soit, le constructeur de caractères fonctionne comme un charme. Je veux enregistrer dans le constructeur de type une classe.Étrange comportement de la macro scala lors de la vérification du type abstrait?

A exécution il n'y a pas de problème pour que:

if (classSymbol.isAbstract) throw new IllegalArgumentException("Provided class is abstract") 

tagger la méthode avec un attribut typetag , si scala n'Erasure pas le temps lors de la compilation.

def createInstance[T: TypeTag]: T 

De toute façon, cela fonctionne. Je ne préfère pas de cette façon, car l'utilisateur peut entrer une classe abstraite et vouloir le créer. Je ne veux pas vérifier l'exception d'argument à l'exécution.

Donc, je pensais que ce serait vraiment cool de vérifier le bon type pendant temps de compilation. Ce est le code complet de la fonction macro :

object ClassCheckMacro { 

    def checkClass[T](x: T): T = macro checkClassImpl[T] 

    def checkClassImpl[T: c.WeakTypeTag](c: blackbox.Context)(x: c.Tree) = { 
    import c.universe._ 
    val symbol = weakTypeOf[T].typeSymbol 
    if (symbol.isAbstract) { 
     c.abort(c.enclosingPosition, s"${symbol.fullName} must be a class") 
    } else { 
     c.Expr(q"($x)") 
    } 
    } 
} 

evertime J'utilise cette macro, je reçois le message d'abort "doit être une classe". Peu importe s'il s'agit d'un type de classe ou d'un type abstrait. Utilisation:

val typeInfo = typeOf[T] 
    val classSymbol = typeInfo.typeSymbol.asClass 
    ClassCheckMacro.checkClass(classSymbol) 

Existe-t-il des conseils pour ce comportement "étrange"?

+0

Avez-vous l'intention 'checkClass (nouveau C)'? –

+0

Oui, une sorte de ça. pour 'new C' je dois mettre le typeSymbol, parce que vous ne pouvez pas créer une nouvelle instance d'un type générique;) –

+0

Je pense que vous ne comprenez pas comment l'invoquer. Étant donné 'class C', essayez' checkClass [C] (null) ', par exemple. –

Répondre

0

x est juste une valeur.

$ scalam -language:_ 
Welcome to Scala 2.12.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92). 
Type in expressions for evaluation. Or try :help. 

scala> import reflect.macros._ 
import reflect.macros._ 

scala> def checkClassImpl[T: c.WeakTypeTag](c: blackbox.Context)(x: c.Tree) = { 
    |  import c.universe._ 
    |  val symbol = weakTypeOf[T].typeSymbol 
    |  if (symbol.isAbstract) { 
    |   c.abort(c.enclosingPosition, s"${symbol.fullName} must be a class") 
    |  } else { 
    |   c.Expr(q"($x)") 
    |  } 
    | } 
checkClassImpl: [T](c: scala.reflect.macros.blackbox.Context)(x: c.Tree)(implicit evidence$1: c.WeakTypeTag[T])c.Expr[T] 

scala> def checkClass[T](x: T): T = macro checkClassImpl[T] 
defined term macro checkClass: [T](x: T)T 

scala> class C 
defined class C 

scala> checkClass[C](null) 
res0: C = null 

scala> abstract class K 
defined class K 

scala> checkClass[K](null) 
<console>:17: error: K must be a class 
     checkClass[K](null) 
        ^

Au milieu de la mise à niveau de l'ordinateur portable de travail Windows 10 ...

+0

Oui, le paramètre est silencieux inutile. Je l'ai essayé sans paramètre auparavant, puis j'ai pensé que la mise en œuvre de la macro a besoin de cela pour récupérer la bonne classe. J'ai mis à jour le projet à scala "2.12.0-M5" mais le même problème encore. En tout cas merci beaucoup pour votre réponse ... :) –