如何实现行为一致但不可混用的Scala opaque类型别名?
问题解决:实现同底层但不可混用的强类型
你希望创建两个基于同一底层类型的类型,它们拥有相同的行为但完全不可混用(类似米和秒不能相加,但同类型可以相加并返回对应类型),但当前使用opaque类型的实现没有达到预期:同类型相加返回底层类型,不同类型还能直接相加。
问题原因分析
你原来的代码中,opaque type myType1 <: foo = foo让myType1成为foo的子类型,这意味着:
- 调用
foo类的+方法时,myType1和myType2都会被自动向上转型为foo,所以不同类型可以互相传入 +方法返回的是foo类型,而非对应的opaque类型
正确实现方案
我们需要让opaque类型不继承foo,而是将Double作为底层类型,然后为每个opaque类型单独定义扩展方法来实现加法逻辑,这样就能保证类型隔离:
object example { // 直接基于Double定义opaque类型,不依赖中间类 opaque type myType1 = Double opaque type myType2 = Double // 为myType1实现转换与加法 extension (d: Double) def toMyType1: myType1 = d extension (mt1: myType1) def +(that: myType1): myType1 = mt1 + that // 可选:提供获取底层值的方法 def value: Double = mt1 // 为myType2实现相同逻辑的方法 extension (d: Double) def toMyType2: myType2 = d extension (mt2: myType2) def +(that: myType2): myType2 = mt2 + that def value: Double = mt2 } import example.{myType1, myType2} import example.{toMyType1, toMyType2, given} val a1 = 1.5.toMyType1 // a1: myType1 val a2 = 2.4.toMyType1 // a2: myType1 val b1 = 3.2.toMyType2 // b1: myType2 val a3 = a1 + a2 // a3: myType1 ✅ 符合预期 // val c1 = a1 + b1 // 编译错误 ✅ 符合预期:类型不匹配,无法将myType2传入myType1的+方法
如果需要复用加法逻辑避免重复代码,可以提取通用工具方法:
object example { opaque type myType1 = Double opaque type myType2 = Double // 通用加法逻辑,通过类型约束复用代码 private def add[T](a: T, b: T)(using ev: T =:= Double): T = ev(a) + ev(b) extension (d: Double) def toMyType1: myType1 = d def toMyType2: myType2 = d extension (mt1: myType1) def +(that: myType1): myType1 = add(mt1, that) def value: Double = mt1 extension (mt2: myType2) def +(that: myType2): myType2 = add(mt2, that) def value: Double = mt2 }
效果验证
- 同类型相加返回对应opaque类型,符合预期
- 不同类型相加直接触发编译错误,实现了严格的类型隔离
- 底层类型均为Double,无额外性能开销,契合opaque类型的设计初衷
内容的提问来源于stack exchange,提问作者t9dupuy
相关产品推荐
相关产品推荐

