如何解决调用Scala quoted Expr的value*扩展方法无法构造的报错
错误原因
Expr.value/valueOrError是依赖quoted.FromExpr[T]类型类的扩展方法,Scala标准库仅对基础类型、字符串、元组、常见集合、样例类等内置了FromExpr实例,你使用的第三方类型ZIO[Any, Any, Any]没有默认的类型类实现,因此编译器无法找到对应的扩展方法,触发编译错误。
解决方法
方案1:运行期取值(推荐,适配全场景)
你不需要在宏执行的编译阶段获取ZioAny实例,直接将expr嵌入到生成的代码中,在生成代码的运行阶段自然就能拿到实际值:
def evaluateNowImpl(expr: Expr[ZioAny])(using Quotes): Expr[UIO[CallGraph]] = { '{ val runtimeZioVal = $expr UIO.succeed(new CallGraph(${Expr(expr.show)}, runtimeZioVal) {}) } }
该方案对静态常量、动态运行时表达式都生效,不需要额外编写类型类实现。
方案2:自定义FromExpr[ZioAny]实例(仅适用于编译期常量场景)
如果你确实需要在宏运行的编译阶段拿到ZioAny的值(例如需要根据ZIO的结构在编译期生成不同逻辑的代码),可以自行实现对应类型类:
given FromExpr[ZioAny] with { def apply(expr: Expr[ZioAny])(using Quotes): Option[ZioAny] = expr match { // 匹配ZIO.succeed包裹的常量表达式 case '{ ZIO.succeed[Any](constValue) } => constValue.value.map(c => ZIO.succeed(c)) // 匹配ZIO.fail包裹的常量表达式 case '{ ZIO.fail[Any](constValue) } => constValue.value.map(c => ZIO.fail(c)) // 按照你的业务需求补充其他ZIO构造器、组合子的匹配逻辑 case _ => None } }
注意该方案仅能处理编译期可确定值的常量表达式,如果传入的io0是依赖运行时参数的动态表达式,expr.value会返回None,无法拿到实际值。
内容的提问来源于stack exchange,提问作者bbarker
相关产品推荐
相关产品推荐

