在 Scala 类型层次结构中途忽略通用参数

Ignoring generic argument halfway through scala type hierarchy

我有一个平行的类型层次结构,它们通常相互引用:一个通过普通泛型,另一个通过类型变量。

但是,其中一个并行层次结构比另一个短,这给我带来了问题。

我在下面提供了一个代码片段,编译器错误被添加为导致问题的行上方的内联注释:

问题是我希望 FooKey 不是通用的,至于 FooKey Foo 的实现究竟如何参数化并不重要。

package com.scalatest

object Database {
  trait PrimaryKey[A <: Entity[A], B <: PrimaryKey[A, B]] {
    this: B =>
  }

  trait Entity[A <: Entity[A]] {
    this: A =>

    type K <: PrimaryKey[A, K]
    val id: K
  }

  //Error:(17, 24) type arguments [com.scalatest.Database.Foo[_],com.scalatest.Database.FooKey] do not conform to trait PrimaryKey's type parameter bounds [A <: com.scalatest.Database.Entity[A],B <: com.scalatest.Database.PrimaryKey[A,B]]
  //  class FooKey extends PrimaryKey[Foo[_], FooKey]
  class FooKey extends PrimaryKey[Foo[_], FooKey]

  trait Foo[A <: Foo[A]] extends Entity[A] {
    this: A =>
    //Error:(24, 19) overriding type K in trait Entity with bounds <: com.scalatest.Database.PrimaryKey[A,Foo.this.K];
    // type K has incompatible type
    //    override type K = FooKey
    override type K = FooKey
  }

  class FooImpl(val id: FooKey) extends Foo[FooImpl]
}

我设法在我的 FooKey 声明中使用存在类型而不是 Foo[_],同时使所有 A 协变,但我仍然剩下第二个错误。

  class FooKey extends PrimaryKey[Foo[A] forSome { type A <: Foo[A] }, FooKey]

这不是真的

for FooKey it doesn't matter how exactly the implementation of Foo is parameterized.

您想用 FooKey 覆盖 K <: PrimaryKey[A, K] 类型,其中 Atrait Entity[A <: Entity[A]] {... 相同 并且您在 trait Foo[A <: Foo[A]] {... 中进行了此覆​​盖,因此 FooKey 必须满足条件 K <: PrimaryKey[A, K] (这不仅仅是上限,因为 K 存在于两侧)每个 A <: Foo[A] 所以 FooKey 应该被普遍量化而不是存在量化。

所以你应该将类型参数添加到 FooKey

  object Database {
    trait PrimaryKey[A <: Entity[A], B <: PrimaryKey[A, B]] {
      this: B =>
    }

    trait Entity[A <: Entity[A]] {
      this: A =>

      type K <: PrimaryKey[A, K]
      val id: K
    }

    class FooKey[A <: Foo[A]] extends PrimaryKey[A, FooKey[A]]

    trait Foo[A <: Foo[A]] extends Entity[A] {
      this: A =>
      override type K = FooKey[A]
    }

    class FooImpl(val id: FooKey[FooImpl]) extends Foo[FooImpl]
  }