Scala中如何让隐式类扩展的Trait实现被编译器识别?
问题分析
你遇到的核心问题是:Processor的类型约束A <: HasFoo[A]要求类型A本身必须是HasFoo[A]的子类,但你用隐式类只是给Bar的实例扩展了foo方法,并没有改变Bar的类型继承关系——Bar依然没有实现HasFoo[Bar],所以编译器会报错。
解决方案
方案一:修改Processor的约束(推荐)
把Processor的类型约束从类型继承改成上下文边界,要求存在隐式的HasFoo[A]实例即可,这样就不需要A本身继承HasFoo。
调整后的完整代码:
// Bar是自动生成的,无法直接修改 final case class Bar(baz: String) trait HasFoo[A] { def foo: A } // 用隐式类为Bar实例扩展HasFoo[Bar]的实现 implicit class BarHasFoo(val bar: Bar) extends HasFoo[Bar] { override def foo: Bar = bar.copy(baz = s"${bar.baz} else") } // 修改Processor的约束为上下文边界,要求隐式存在HasFoo[A] class Processor[A: HasFoo]() {} // 现在可以正常编译 val process = new Processor[Bar]()
你也可以把隐式类换成直接提供HasFoo[Bar]的隐式实例,写法更简洁(同时推荐调整HasFoo的定义,更符合Scala类型类的设计习惯):
// 调整HasFoo trait的定义 trait HasFoo[A] { def foo(a: A): A } // Bar是自动生成的,无法直接修改 final case class Bar(baz: String) // 提供HasFoo[Bar]的隐式实例 implicit val barHasFoo: HasFoo[Bar] = new HasFoo[Bar] { override def foo(bar: Bar): Bar = bar.copy(baz = s"${bar.baz} else") } // Processor使用上下文边界约束 class Processor[A: HasFoo]() {} // 正常编译 val process = new Processor[Bar]()
方案二:包装类(无法修改Processor时使用)
如果不能修改Processor的类型约束,只能通过包装Bar来满足A <: HasFoo[A]的要求:
// Bar是自动生成的,无法直接修改 final case class Bar(baz: String) trait HasFoo[A] { def foo: A } // 定义包装类,继承HasFoo[BarWrapper] class BarWrapper(val underlying: Bar) extends HasFoo[BarWrapper] { override def foo: BarWrapper = new BarWrapper(underlying.copy(baz = s"${underlying.baz} else")) } // 提供隐式转换,方便自动把Bar转成BarWrapper implicit def barToWrapper(bar: Bar): BarWrapper = new BarWrapper(bar) // 使用包装类作为Processor的类型参数 val process = new Processor[BarWrapper]()
这种方式的缺点是你需要处理BarWrapper而非原始的Bar,如果业务逻辑必须直接使用Bar,该方案不适用。
内容的提问来源于stack exchange,提问作者jdelman
相关产品推荐
相关产品推荐

