我正在尝试编写一个宏,该宏在需要时隐含地实现了播放格式的实例:
class FormattableImpl(override val c: whitebox.Context) extends Utils(c) {
import c.universe._
def materializeFormatImpl[T : c.WeakTypeTag]: c.Expr[play.api.libs.json.Format[T]] = {
val tpe = implicitly[c.WeakTypeTag[T]].tpe
val x = c.Expr[play.api.libs.json.Format[T]](q" com.ubookr.macros.Json.format[$tpe] ")
println(show(x))
x
}
}
object Format {
implicit def materializeFormat[T]: play.api.libs.json.Format[T] = macro FormattableImpl.materializeFormatImpl[T]
}
这对于非参数类型的效果很好(例如
case class Apple(id: Long, name: String)
val x = materializeFormat[Apple]
)。
它也适用于收藏
val xx = materializeFormat[Seq[Apple]]
当我尝试将其用于自己的参数化类型时,它会失去类型参数的值:
case class Proxy[+T](id: Long, name: String)
val xxx = materializeFormat[Proxy[Apple]]
响应
[error] package.scala:112: type mismatch;
[error] found : play.api.libs.json.OFormat[com.ubookr.macros.Proxy[Nothing]]
[error] required: play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]]
[error] Note: com.ubookr.macros.Proxy[Nothing] <: com.ubookr.macros.Proxy[Apple], but trait Format is invariant in type A.
[error] You may wish to define A as +A instead. (SLS 4.5)
[error] val xxx: Any = com.ubookr.macros.Format.materializeFormat[Proxy[Apple]]
[error]
这是有道理的,因为弱typetag不知道T。我的第一个问题是为什么与seq ??
正确起作用。但是,我想出了我认为应该是可行的解决方法:
def materializeProxy[T]: play.api.libs.json.Format[Proxy[T] = macro FormattableImpl.materializeProxyImpl[T]
materializeProxyImpl
的实现是
def materializeProxyImpl[T : c.WeakTypeTag]: c.Expr[play.api.libs.json.Format[Proxy[T]]] = materializeFormatImpl[Proxy[T]]
materializeFormatImpl
中的println
现在正确地显示了参数类型t的实际值:
Expr[play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]]](com.ubookr.macros.Json.format[com.ubookr.macros.Proxy[Apple]])
但是我仍然立即遇到相同的错误:
[error] package.scala:112: type mismatch;
[error] found : play.api.libs.json.OFormat[com.ubookr.macros.Proxy[Nothing]]
[error] required: play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]]
[error] Note: com.ubookr.macros.Proxy[Nothing] <: com.ubookr.macros.Proxy[Apple], but trait Format is invariant in type A.
[error] You may wish to define A as +A instead. (SLS 4.5)
[error] val xxx: Any = Format.materializeProxy[Apple]
[error]
我尝试将materializeProxy
和materializeProxyImpl
上的类型注释分别更改为Any
和Tree
,但是语法错误仍然发生,这向我表明,不匹配发生在宏引擎内部的某个地方。
我做错了什么吗?还是这是宏引擎中的错误?
似乎播放JSON宏观实现并不期望通用案例类。它正在输出
(
(JsPath "id").format[Long] and
(JsPath "name").format[String]
)(Proxy.apply, unlift(Proxy.unapply)
我修改了游戏宏,以便它输出
(
(JsPath "id").format[Long] and
(JsPath "name").format[String]
)(Proxy.apply[Apple], unlift(Proxy.unapply[Apple])
现在它可以按预期工作。