0
我嘗試寫隱含物化播放格式化實例在需要時宏:編譯錯誤泛型類型
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]
這是有道理的,因爲WeakTypeTag不知道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]]
的println
在materializeFormatImpl
現在正確顯示參數類型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
類型標註,但語法錯誤仍然出現,反映走勢將轉我發現類型不匹配發生在宏引擎的內部。
我做錯了什麼?或者這是宏引擎中的一個錯誤?
嗯,我認爲它對Seq正確工作的事實是一個線索。 JsMacroImpl代碼具有Seq參數的顯式幫助器。我懷疑發生錯誤是因爲播放宏忽略了我的類型參數。 –
這是一個已知的限制,現在已修復:https://github.com/playframework/playframework/pull/5384 – cchantep