Почему равенство типов терпит неудачу, но соответствие типов успешно выполняется в этом макросе?

Я пытаюсь определить тип параметра, переданного в макрос во время компиляции. Кажется, это работает, когда я использую <:< но не тогда, когда я использую =:=. Не знаю почему. Кто-нибудь может указать мне правильное направление? Я включил пример кода ниже.

этот макрос:

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: %sn", param.splice) }
    } else if (param.actualType.<:<(c.universe.typeOf[Int])) {
      c.universe.reify { printf("int: %dn", param.splice) }
    } else {
      c.universe.reify { printf("any: %sn", param.splice) }
    }
  }
}

вызывается этим кодом:

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

case object Blah

возвращает:

string: Hi
int: 1
any: Blah

но если я проверю равенство типов (=:=), а не макрос возвращает:

any: Hi
any: 1
any: Blah

любая помощь была бы очень признательна.

1 ответов


это потому, что типа "Hi" не только String, это более конкретный тип - String("Hi"), что означает, что этот тип содержит информацию о том, что он представляет конкретный строковый литерал.

та же ситуация происходит с literal - это Int(1) не только Int.

можно использовать widen метод on Type чтобы удалить информацию о постоянных значениях:

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