【问题标题】:How can I use generics for a Scala (2.12) macro?如何将泛型用于 Scala (2.12) 宏?
【发布时间】:2019-01-21 12:35:40
【问题描述】:

我已经定义了一个简单的通用宏:

object MyMacro {

  def readWrite[T](readParse: String => T, label: String, format: T => String): Unit = macro readWriteImpl[T]

  def readWriteImpl[T: c.WeakTypeTag](c: Context)(readParse: c.Expr[String => T], label: c.Expr[String], format: c.Expr[T => String]): c.Tree = {
    import c.universe._

    q"""
    def read[WIRE](path: Path, reader: Transceiver[WIRE], isMapKey: Boolean = false): T =
      reader.readString(path) match {
        case null => null.asInstanceOf[T]
        case s => Try( $readParse(s) ) match {
          case Success(d) => d
          case Failure(u) => throw new ReadMalformedError(path, "Failed to parse "+$label+" from input '"+s+"'", List.empty[String], u)
        }
      }

    def write[WIRE](t: T, writer: Transceiver[WIRE], out: Builder[Any, WIRE]): Unit =
      t match {
        case null => writer.writeNull(out)
        case _    => writer.writeString($format(t), out)
      }
      """
  }
}

在一个单独的编译单元中,我这样使用它:

object DurationTypeAdapterFactory extends TypeAdapter.=:=[Duration] {
  MyMacro.readWrite[Duration]((s: String) => Duration.parse(s), "Duration", (t: Duration) => t.toString)
}

编译时,编译器抱怨它不知道 T:

[error] /Users/me/git/ScalaJack/core/src/main/scala/co.blocke.scalajack/typeadapter/TimePrimitives.scala:13:30: not found: type T
[error]   MyMacro.readWrite[Duration]((s: String) => Duration.parse(s), "Duration", (t: Duration) => t.toString)
[error] 

它不喜欢我的准引用中的“T”引用,我有点理解。我怎样才能表示传递给 quasiquote 内的 readWriteImpl 的 T 参数,以便它正确解包?

【问题讨论】:

    标签: scala scala-macros scala-quasiquotes


    【解决方案1】:

    使用标签检查类型或使用=:=将其与其他类型进行比较,或在扩展中使用。

    例如,

    scala 2.13.0-M5> def fImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = { import c._, universe._
                   | q"null.asInstanceOf[${implicitly[c.WeakTypeTag[A]].tpe}]" }
    fImpl: [A](c: scala.reflect.macros.blackbox.Context)(a: c.Expr[A])(implicit evidence$1: c.WeakTypeTag[A])c.universe.Tree
    
    scala 2.13.0-M5> import language.experimental.macros ; def f[A](a: A): A = macro fImpl[A]
    import language.experimental.macros
    defined term macro f: [A](a: A)A
    
    scala 2.13.0-M5> f(42)
    res2: Int = 0
    
    scala 2.13.0-M5> f("")
    res3: String = null
    

    【讨论】:

    • 这让我摆脱了被卡住的这一点......但打开了一个新的宏观问题,我将作为一个新问题发布。
    • 他们应该称它们为stickos,而不是宏。
    猜你喜欢
    • 2020-12-15
    • 2014-10-30
    • 1970-01-01
    • 2021-11-18
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    相关资源
    最近更新 更多