为什么 scala 不将这种类型的 lambda 与底层类型统一起来?

Why scala does not unify this type lambda with underlying type?

trait A {
  type T
  def test(t: T): Unit
}

case class B[S <: A](a: S, t : S#T) {
  def test() = a.test(t) // Error: type mismatch;
    // found   : B.this.t.type (with underlying type S#T)
    // required: B.this.a.T
}

我期望上面的编译是错误的吗?我的代码可以修复吗?

我可以想出编码(为了简化删除了类型参数):

scala> :paste
// Entering paste mode (ctrl-D to finish)

def test0(a: A)(t : a.T) = a.test(t) 

abstract class B{
  val a: A
  val t: a.T
  def test = a.test(t)
}

// Exiting paste mode, now interpreting.

test0: (a: A)(t: a.T)Unit
defined class B

另一方面,这不适用于 case 类 参数(也不适用于 类')。

您的编码不起作用的原因之一:

scala> def test1(a: A)(t : A#T) = a.test(t) 
<console>:12: error: type mismatch;
 found   : t.type (with underlying type A#T)
 required: a.T
       def test1(a: A)(t : A#T) = a.test(t)

重要的部分是 required: a.T(相对于 A#T)。 A 中的测试方法不接受任何 T,它接受 T this.T,或者换句话说,属于 A.

的一个特定实例的 T

编译器没有足够的证据表明 S#T 可以在具体实例中用作 test 的参数。

考虑这个弱化 scala 编译器的 hypotecical 示例

trait A2 extends A{
  type T <: AnyRef
}

class A3 extends A2{
  override type T = Integer

  def test(t: Integer): Unit = println(t * 2)
}

所以 B[A2] 应该接受 A3 的实例以及 <: AnyRef 的任何东西,而 A3 恰好需要 Integer 作为它自己的 test 实施

您可以在 B 的定义中捕获具体类型,以确保将使用什么类型

case class B[S <: A, ST](a: S {type T = ST}, t: ST) {
  def test() = a.test(t) 
}

您可以使用依赖类型 a.T:

而不是类型投影
trait A {
  type T
  def test(t: T): Unit
}

case class B[S <: A](a: S)(t : a.T) {
  def test() = a.test(t)
}