2013-05-30 16 views
6

Sto provando a determinare il tipo di parametro passato in una macro in fase di compilazione. Sembra funzionare quando uso <:< ma non quando uso =:=. Non sono sicuro del perché. Qualcuno può indicarmi la giusta direzione? Ho incluso il codice di esempio qui sotto.Perché l'uguaglianza di tipo non riesce, ma la conformità del tipo ha esito positivo in questa macro?

Questa macro:

import language.experimental.macros 
import scala.reflect.macros.Context 

object Macros { 
    def say(param: Any): Unit = macro impl 

    def impl(c: Context)(param: c.Expr[Any]): c.Expr[Unit] = { 
    if (param.actualType.<:<(c.universe.typeOf[String])) { 
     c.universe.reify { printf("string: %s\n", param.splice) } 
    } else if (param.actualType.<:<(c.universe.typeOf[Int])) { 
     c.universe.reify { printf("int: %d\n", param.splice) } 
    } else { 
     c.universe.reify { printf("any: %s\n", param.splice) } 
    } 
    } 
} 

Chiamato da questo codice:

object Test extends App { 
    Macros.say("Hi") 
    Macros.say(1) 
    Macros.say(Blah) 
} 

case object Blah 

Returns:

string: Hi 
int: 1 
any: Blah 

Ma se controllo per l'uguaglianza tipo (=:=) invece i rendimenti macro:

any: Hi 
any: 1 
any: Blah 

Qualsiasi aiuto sarebbe molto apprezzato.

risposta

7

Questo perché il tipo di "Hi" non è solo String, è il tipo più specifico - String("Hi"), che significa che questo tipo contiene informazioni che rappresenta il letterale di stringa concreto.

La stessa situazione si verifica con il valore letterale 1 - il tipo è Int(1), non solo Int.

È possibile utilizzare widen metodo su Type mettere a nudo le informazioni su valori costanti:

object Macros { 
    def say(param: Any): Unit = macro impl 

    def impl(c: Context)(param: c.Expr[Any]): c.Expr[Unit] = { 
    if (param.actualType.widen.=:=(c.universe.typeOf[String])) { 
     c.universe.reify { printf("string: %s\n", param.splice) } 
    } else if (param.actualType.widen.=:=(c.universe.typeOf[Int])) { 
     c.universe.reify { printf("int: %d\n", param.splice) } 
    } else { 
     c.universe.reify { printf("any: %s\n", param.splice) } 
    } 
    } 
} 
+5

+1, mi ha battuto ad esso. Vale la pena notare che 'Int (1)' è chiamato _singleton type_, cioè un tipo che è solo abitato dal valore '1', e che' =: = 'funzionerà come previsto con argomenti non letterali (ad esempio' val i = 1; Macros.say (i) '). –

+0

Brillante. Grazie ad entrambi! –

Problemi correlati