我一直在尝试编写一个生成抽象类型的类标记的宏。
我概括了https://stackoverflow.com/a/19502658/2859613中提供的代码:
object Macro {
import scala.reflect.ClassTag
import scala.reflect.macros.blackbox
def typeClassTag[A: c.WeakTypeTag]
(c: blackbox.Context): c.Expr[ClassTag[A]] = {
import c.universe._
val A = c.prefix.tree.tpe.member(weakTypeOf[A].typeSymbol.name).typeSignature
c.Expr(q"implicitly[ClassTag[$A]]").asInstanceOf[c.Expr[ClassTag[A]]]
}
}
使用类型类进行测试,抽象类型与路径无关:
import scala.language.experimental.macros
import scala.reflect.ClassTag
import Macro._
trait GatewayService {
type Request
type Response
def requestTag : ClassTag[Request] = macro typeClassTag[Request]
def responseTag: ClassTag[Response] = macro typeClassTag[Response]
}
trait TransferRequest
trait TransferResponse
trait TransferService extends GatewayService {
type Request = TransferRequest
type Response = TransferResponse
}
class TransferServiceImpl extends TransferService
"TransferServiceImpl requestTag and responseTag" should {
"equal ClassTag[TransferRequest] and ClassTag[TransferResponse] respectively" in {
val transferService = new TransferServiceImpl
transferService.requestTag shouldEqual implicitly[ClassTag[TransferRequest]]
transferService.responseTag shouldEqual implicitly[ClassTag[TransferResponse]]
}
}
上面的代码编译并且测试成功。当抽象类型不依赖于路径时,宏将按预期工作。
现在看看这个类型类尝试使用与路径相关的抽象类型调用此宏:
import scala.language.experimental.macros
import scala.reflect.ClassTag
import Macro._
trait GatewayFrontend {
type Service <: GatewayService // GatewayService was defined in the code above
def requestTag : ClassTag[Service#Request] = macro typeClassTag[Service#Request]
def responseTag: ClassTag[Service#Response] = macro typeClassTag[Service#Response]
}
trait TransferFrontend extends GatewayFrontend {
type Service = TransferService // TransferService was defined in the code above
}
class TransferFrontendImpl extends TransferFrontend
"TransferFrontendImpl requestTag and responseTag" should {
"equal ClassTag[TransferRequest] and ClassTag[TransferResponse] respectively" in {
val transferFrontend = new TransferFrontendImpl
transferFrontend.requestTag shouldEqual implicitly[ClassTag[TransferRequest]]
transferFrontend.responseTag shouldEqual implicitly[ClassTag[TransferResponse]]
}
}
代码甚至没有编译。我明白了:
[error] No ClassTag available for <notype>
[error] transferFrontend.requestTag shouldEqual implicitly[ClassTag[TransferRequest]]
[error] ^
[error]
[error] No ClassTag available for <notype>
[error] transferFrontend.responseTag shouldEqual implicitly[ClassTag[TransferResponse]]
[error] ^
[error]
[error] two errors found
[error] (macro-utils/test:compileIncremental) Compilation failed
如何更改宏实现以支持此用例?
我认为这需要某种递归,但我仍然是一个scala宏新手,我对如何使用宏的递归没有任何线索。
那里有没有支持开箱即用的图书馆?