我想使用抽象类型和类型细化对两种类型之间的函数依赖进行编码。
trait BaseA {
type M
type P <: BaseB.Aux[M]
def f(m: M): Unit
}
trait BaseB {
type M
def m(): M
}
object BaseB {
type Aux[M0] = BaseB { type M = M0 }
}
这意味着A
仅在内部具有相同类型B
的情况下才能与M
一起使用。
通过以下具体课程
class A extends BaseA {
type M = Int
type P = B
def f(m: Int): Unit = {
println("a")
}
}
class B extends BaseB {
type M = Int
def m(): M = 1
}
所以现在它们的Int
类型都为M
,但是以下代码无法编译
val a: BaseA = new A
val b: BaseB = new B
def f[T <: BaseA](a: T, b: T#P): Unit = {
a.f(b.m())
}
编译器告诉我a.f
在这里期望的是路径依赖类型a.M
,但是得到了b.M
。
这里的问题是我该如何表达我只需要在类型级别而不是实例级别匹配的M
类型这一事实?或者如何防止M
中的def f(m: M): Unit
成为路径相关类型?
谢谢!
答案 0 :(得分:1)
我认为,该问题来自b
与类型T
的关联,a
可能是子类< T
的/ em>可能会覆盖M
成为其他东西,从而使两个对象不兼容。例如:
class A2 extends BaseA {
type M = String
type P = B2
def f(s: String): Unit = {
println(s)
}
}
class B2 extends BaseB {
type M = String
def m(): M = "foo"
}
val a: BaseA = new A
val b: BaseB = new B2
f[BaseA](a, b)
好像您的f
要编译,那么所有这些也应该编译。
您可以根据b
来设置a.P
的类型:
def f(a: BaseA)(b: a.P): Unit
或者我认为,由于对类没有兼容的类型限制,因此简化了整个过程,而是要求它们在相互作用时必须是另一个的子类:
trait BaseA {
type M
def f(m: M): Unit
}
trait BaseB {
type M
def m(): M
}
class A extends BaseA {
type M = Int
def f(m: Int): Unit = {
println("a")
}
}
class B extends BaseB {
type M = Int
def m(): M = 1
}
val a: A = new A
val b: B = new B
def f(a: BaseA, b: BaseB)(implicit sub: b.M <:< a.M): Unit = {
a.f(sub(b.m()))
}
f(a, b)
或者最后,考虑是否需要将它们完全成为依赖于路径的类型;它们可以是常规的泛型类型参数吗?
trait BaseA[-M] {
def f(m: M): Unit
}
trait BaseB[+M] {
def m(): M
}
class A extends BaseA[Int] {
def f(m: Int): Unit = {
println("a")
}
}
class B extends BaseB[Int] {
def m(): Int = 1
}
def f[T](a: BaseA[T], b: BaseB[T]): Unit = {
a.f(b.m())
}