提问人:t9dupuy 提问时间:3/18/2023 更新时间:3/19/2023 访问量:61
如何实现行为相同但不能一起使用的类型别名
How to implement type aliases that behave the same but cannot be used together
问:
我想实现两个类型别名,它们“引用”相同的基础类型(因此它们的行为相同,具有相同的方法),但不能混合在一起。
代码示例如下:
object example {
case class foo(value: Double):
def +(that: foo): foo = foo(value + that.value)
opaque type myType1 <: foo = foo
opaque type myType2 <: foo = foo
extension (d: Double)
def toMyType1: myType1 = new myType1(d)
def toMyType2: myType2 = new myType2(d)
}
import example.{myType1, myType2}
import example.{toMyType1, toMyType2}
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: foo but wanted a3: myType1
val c1 = a1 + b1 //c1: foo but wanted COMPILATION ERROR (can't add "myType1" and "myType2")
通缉行为 :
- 可以将两个值相加,从而产生一个新的(相同的
myType1
myType1
myType2
) - 的值不能相加(编译错误)
myType1
myType2
这背后的想法是:你不能把米和秒加在一起,即使用米加米或用秒加秒是一样的。
郑重声明:我认为使用 for 类型别名会使编译器将 and 视为两种不同的类型(禁止在它们之间添加),即使它们实际上是相同的类型。opaque
myType1
myType2
答:
2赞
Mateusz Kubuszok
3/19/2023
#1
您应该使用类型类。由于您使用的是 Scala 3,因此您可以在 Scala 3 中使用对类型类的改进支持:
object example {
opaque type myType1 = Double
opaque type myType2 = Double
extension (d: Double)
def toMyType1: myType1 = d
def toMyType2: myType2 = d
// type class definition
trait Semigroup[A]:
extension (a1: A) def +(a2: A): A
// type class instance
private val semigroupDouble = new Semigroup[Double]:
extension (a1: Double) def +(a2: Double): Double = a1 + a2
given Semigroup[myType1] = semigroupDouble
given Semigroup[myType2] = semigroupDouble
}
import example.*
val a1 = 1.5.toMyType1 //a1: myType1
val a2 = 2.4.toMyType1 //a2: myType1
val b1 = 3.2.toMyType2 //b1: myType2
a1 + a2 // myType1
//a1 + b1 // compilation error
评论
0赞
t9dupuy
3/20/2023
该性状可以用于高等种类的类型吗?喜欢?如果是这样,我该如何实例化该值? ?Semigroup[A]
trait Semigroup[A[_]]
val semigroupHigher = new Semigroup[SomeType[SomeOtherType]]
0赞
Mateusz Kubuszok
3/20/2023
从理论上讲,您可以使用然后在类型上进行一些模式匹配......但一般来说,最好为不同的类型提供单独的类型类。所以我建议改用例如.或者,使用 Cats 方法:分离,在专用方法中组合 2(假设)采用类型参数或提供 .在实践中更容易掌握和使用。A <: AnyKind
inline def
given listSemigroup[A]: Semigroup[List[A]] = ...
trait SemigroupK[F[_]]
F[A]
++
[A]
given fromSemigroupK[F[_], A](using SemigroupK[F]): Semigroup[F[A]]
评论
foo
+
foo