2013-05-30 11 views
6

Próbuję określić typ parametru przekazywany do makra w czasie kompilacji. Wydaje się działać, gdy używam <:<, ale nie wtedy, gdy używam =:=. Nie jestem pewien dlaczego. Czy ktoś może wskazać mi właściwy kierunek? Podałem przykładowy kod poniżej.Dlaczego wpisuje się błąd równości, ale w tym makrze wpisuje się poprawność zgodności?

To makro:

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) } 
    } 
    } 
} 

Wywoływana przez ten kod:

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

case object Blah 

Powroty:

string: Hi 
int: 1 
any: Blah 

Ale jeśli sprawdzeniu równości typu (=:=) zamiast makro zwrotów:

any: Hi 
any: 1 
any: Blah 

Każda pomoc będzie bardzo doceniana.

Odpowiedz

7

To dlatego, że typ "Hi" to nie tylko String, to jest bardziej specyficzny typ - String("Hi"), co oznacza, że ​​ten typ zawiera informację, że reprezentuje konkretny ciąg literału.

Ta sama sytuacja występuje w przypadku literału 1 - jego typ to Int(1), a nie tylko Int.

Można użyć widen sposób na Type rozebrać informacje o wartościach stałych:

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, pokazał mi do niego. Warto zauważyć, że 'Int (1)' jest nazywane _singleton type_, tzn. Typem, który jest tylko zamieszkany przez wartość '1', i że' =: = 'będzie działało zgodnie z oczekiwaniami z nie-literalnymi argumentami (np.' Val i = 1; Macros.say (i) '). –

+0

Brilliant. Dziękuję wam obu! –

Powiązane problemy