获取Scala3宏中的类型信息

44u64gxh  于 2022-11-09  发布在  Scala
关注(0)|答案(3)|浏览(224)

我正在努力获取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] = ...

如何在编译时的宏扩展期间获得QAuthUser类型的信息?

k97glaaz

k97glaaz1#

一种可能的解决方案是对带引号的表达式使用模式匹配
因此,例如,您可以定义用于检索编译时类型的方法:

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
}

这是一个相当复杂的技巧(而且可扩展性不是很强,因为您必须添加每个类型),所以对我所说的一切都要持保留态度……我认为存在一种更清晰的解决方案,这取决于您特定的应用程序逻辑:)

jbose2ul

jbose2ul2#

限定(参见:Scala 3 Book: Context Bounds)函数中参数的类型可以通过多种方式实现。

  • 这是错误的*(Ty Dmytro!):使用如下的泛型参数时:[T : Type]是类型的别名
  • 更正*:在使用类似于[T : R]的泛型参数时,我们使用的是语法糖类,它表示R[T]类型的隐式参数

对于许多应用程序,包括您的应用程序,限制我们的泛型参数的类型可能是有益的。

主要有两个界限,一个上界和一个下界。

上界例如[T <: U]指定T必须是U类型,或者是U的子类
下限例如[T >: U]指定T必须是U类型,或者是U的超类
可以通过先指定下限然后指定上限来限制这两个界限,例如[T >: Cat <: Animal]

42fyovps

42fyovps3#

如果Q和R是特例(NotUsed,Done,..),我已经解决了这个问题在Q和R的序列化程序中,这个想法来自于Lagom框架。

相关问题