Scala内联方法f2类型推断失败的原因及无Schema[T]解决办法?
Scala中无Schema[T]约束下实现f2的技巧
我编写了如下代码,其中f1可正常运行,但f2编译失败。请问有没有技巧能让f2在不使用Schema[T]的情况下正常工作?
trait Base trait Schema[T <: Base]: given Schema[T] = this class Sub1 extends Base object Sub1 extends Schema[Sub1] class Sub2 extends Base object Sub2 extends Schema[Sub2] trait Container[T <: Base] object Container: import scala.compiletime.erasedValue object C1 extends Container[Sub1] object C2 extends Container[Sub2] def f1[T <: Base : Schema]: Container[T] = summon[Schema[T]] match case Sub1 => C1 case Sub2 => C2 inline def f2[T <: Base]: Container[T] = inline erasedValue[T] match case _: Sub1 => C1 case _: Sub2 => C2
问题原因
f2编译失败的核心原因是:编译器无法自动将Container[Sub1](即C1的类型)推导为Container[T],哪怕编译期通过erasedValue[T]已经确定T就是Sub1,类型系统仍需要显式的类型一致性保证。
解决方案
利用Scala 3的编译期内联特性,结合安全的asInstanceOf类型转换即可解决。因为inline match会在编译期展开,此时T的具体类型已经确定,所以转换不会有运行时风险:
inline def f2[T <: Base]: Container[T] = inline erasedValue[T] match case _: Sub1 => C1.asInstanceOf[Container[T]] case _: Sub2 => C2.asInstanceOf[Container[T]]
补充说明
如果想避免显式的asInstanceOf,也可以通过给C1/C2添加更通用的类型注解实现,但这种方式可读性稍差:
object C1 extends Container[Sub1] with Container[T] forSome { type T <: Base } object C2 extends Container[Sub2] with Container[T] forSome { type T <: Base }
不过第一种方案更直接且安全,因为编译期已经确保T与Sub1/Sub2完全匹配,asInstanceOf在这里只是帮助编译器完成类型推导,不会引入运行时错误。
内容的提问来源于stack exchange,提问作者esse
相关产品推荐
相关产品推荐

