Scala中函数隐式转换的部分统一算法全部失败,如何解决?
Scala普通函数隐式转换为自定义
:=> trait的编译问题及解决方案 问题场景
尝试将Scala普通函数隐式转换为自定义的:=> trait类型,代码如下:
object UnificationOnConversionFromFn { trait :=>[I, R] implicit def fromVanilla[I, R]( vanilla: I => R ): I :=> R = ??? // fail implicit def fromVanilla2[I, R, F <: I => R]( vanilla: F ): I :=> R = ??? // fail implicit def fromVanilla3[I, R, F[A, B] <: A => B]( vanilla: F[I, R] ): I :=> R = ??? // fail lazy val _fn0: Int :=> Int = { val a: Int :=> Int = fromVanilla { v => v + 1 } val b: Int :=> Int = { v => v + 1 } b } }
报错信息
三个隐式转换方法均编译失败,报错为:
UnifyingConversionFromFn.scala:27:28: missing parameter type
解决方案(不修改现有业务代码)
1. 基于Scala宏的类型补全方案
将隐式转换方法改造为宏实现,在宏编译阶段根据目标类型Int :=> Int反推参数v的类型为Int,自动补全匿名函数的参数类型:
import scala.language.experimental.macros import scala.reflect.macros.blackbox object UnificationOnConversionFromFn { trait :=>[I, R] implicit def fromVanilla[I, R](vanilla: I => R): I :=> R = macro fromVanillaImpl[I, R] def fromVanillaImpl[I: c.WeakTypeTag, R: c.WeakTypeTag](c: blackbox.Context)(vanilla: c.Tree): c.Tree = { import c.universe._ // 提取目标类型的I参数 val iType = weakTypeTag[I].tpe // 检查匿名函数并补全参数类型 val typedFn = vanilla match { case Function(List(ValDef(_, name, _, _)), body) => Function(List(ValDef(Modifiers(), name, TypeTree(iType), EmptyTree)), body) case _ => vanilla } // 生成转换后的实例(可替换为具体业务逻辑) q"new :=>[$iType, ${weakTypeTag[R].tpe}] {}" } // 保留原有的fromVanilla2、fromVanilla3(宏实现可覆盖隐式转换逻辑) lazy val _fn0: Int :=> Int = { val a: Int :=> Int = fromVanilla { v => v + 1 } val b: Int :=> Int = { v => v + 1 } b } }
Scala 2.x需添加macro paradise依赖启用宏特性,Scala 3可直接使用inline宏简化实现。
2. 自定义Scala编译器插件
编写编译器插件,在typer类型检查阶段拦截目标类型为:=>[I, R]的隐式转换请求,先提取I的类型,再为匿名函数的参数自动添加类型标注,补全后再执行常规类型检查,全程无需修改业务代码。
3. 切换至Scala 3并启用语言特性
Scala 3的类型推导逻辑更灵活,开启-language:implicitConversions编译选项后,编译器可直接根据目标类型Int :=> Int反推匿名函数的参数类型为Int,现有代码无需修改即可通过编译。
内容的提问来源于stack exchange,提问作者tribbloid
相关产品推荐
相关产品推荐

