获取Scala3宏中类型的信息
Get information of type in Scala3 macro
我正在努力获取 Scala3 宏实现中的类型信息。我会通过代码来解释问题。
这是应用程序逻辑:
object BlockServiceImpl extends BlockService:
def authenticateUser0() = new ServiceCall[AuthUser,AuthUserResponse]:
def invoke(request: AuthUser): Future[AuthUserResponse] =
println("BlockServiceImpl authenticateUser0 called")
Future.successful(AuthUserResponse("test"))
现在,对于我想在宏的帮助下创建端点的逻辑。
defineRoute("POST","/v1/block",BlockServiceImpl.authenticateUser0)
这是内联方法:
inline def defineRoute[Q: RootJsonFormat ,R: RootJsonFormat](method: String, uri: String,inline call: () => ServiceCall[Q,R]): AkkaHttpCall = ${ methodImpl[Q,R]('uri, 'call)}
这是宏的实现:
def methodImpl[Q: Type,R: Type](uri: Expr[String],expr: Expr[Function0[ServiceCall[Q,R]]])(using ctx: Quotes): Expr[AkkaHttpCall] = ...
如何在编译时的宏展开时得到Q
是AuthUser
类型的信息?
一种可能的解决方案是对引用的表达式使用模式匹配。
因此,例如,您可以定义一个用于检索编译时类型的方法:
def tag[A <: AnyKind] = throw new IllegalStateException("use it only to pattern match types")
然后,在宏扩展中,您可以执行模式匹配为:
'{ tag[Q] } match {
case '{ tag[AuthUser] } => // here I am sure that Q is AuthUser, since Q is matched with AuthUser
}
这是一个绝妙的技巧(并且不是很容易扩展,因为您必须添加每种类型)所以对我所说的一切持保留态度...我认为存在更清晰的解决方案取决于您的特定应用程序逻辑:)
绑定函数中参数的类型可以通过多种方式实现。
当像这样使用泛型参数时:[T : Type]
我们正在为类型设置别名
对于许多应用程序,包括您的应用程序,限制我们的通用参数的类型可能是有益的。
有两个主要界限,“上限”和“下限”。
“上限”,例如[T <: U]
指定 T 必须是 U
类型,或者是 U
的子class
“下限”,例如[T >: U]
指定 T 必须是 U
类型,或者是 U
的超 class
可以限制两个边界,首先指定下限,然后指定上限,例如[T >: Cat <: Animal]
如果 Q 和 R 是特殊情况(NotUsed、Done、..),我已经通过将信息放入 Q 和 R 的序列化器中解决了这个问题。这个想法来自 Lagom 框架。
我正在努力获取 Scala3 宏实现中的类型信息。我会通过代码来解释问题。
这是应用程序逻辑:
object BlockServiceImpl extends BlockService:
def authenticateUser0() = new ServiceCall[AuthUser,AuthUserResponse]:
def invoke(request: AuthUser): Future[AuthUserResponse] =
println("BlockServiceImpl authenticateUser0 called")
Future.successful(AuthUserResponse("test"))
现在,对于我想在宏的帮助下创建端点的逻辑。
defineRoute("POST","/v1/block",BlockServiceImpl.authenticateUser0)
这是内联方法:
inline def defineRoute[Q: RootJsonFormat ,R: RootJsonFormat](method: String, uri: String,inline call: () => ServiceCall[Q,R]): AkkaHttpCall = ${ methodImpl[Q,R]('uri, 'call)}
这是宏的实现:
def methodImpl[Q: Type,R: Type](uri: Expr[String],expr: Expr[Function0[ServiceCall[Q,R]]])(using ctx: Quotes): Expr[AkkaHttpCall] = ...
如何在编译时的宏展开时得到Q
是AuthUser
类型的信息?
一种可能的解决方案是对引用的表达式使用模式匹配。
因此,例如,您可以定义一个用于检索编译时类型的方法:
def tag[A <: AnyKind] = throw new IllegalStateException("use it only to pattern match types")
然后,在宏扩展中,您可以执行模式匹配为:
'{ tag[Q] } match {
case '{ tag[AuthUser] } => // here I am sure that Q is AuthUser, since Q is matched with AuthUser
}
这是一个绝妙的技巧(并且不是很容易扩展,因为您必须添加每种类型)所以对我所说的一切持保留态度...我认为存在更清晰的解决方案取决于您的特定应用程序逻辑:)
绑定函数中参数的类型可以通过多种方式实现。
当像这样使用泛型参数时:[T : Type]
我们正在为类型设置别名
对于许多应用程序,包括您的应用程序,限制我们的通用参数的类型可能是有益的。
有两个主要界限,“上限”和“下限”。
“上限”,例如[T <: U]
指定 T 必须是 U
类型,或者是 U
“下限”,例如[T >: U]
指定 T 必须是 U
类型,或者是 U
可以限制两个边界,首先指定下限,然后指定上限,例如[T >: Cat <: Animal]
如果 Q 和 R 是特殊情况(NotUsed、Done、..),我已经通过将信息放入 Q 和 R 的序列化器中解决了这个问题。这个想法来自 Lagom 框架。