为什么Scala编译器会考虑类型,而为其赋值的类型却不同?

问题描述

我有一个简单的类来表示向量,因此不同长度的向量可以解析为不同的类型。但是,在实现zip方法时遇到一些困难。这是我所做工作的最小化版本,以及我觉得有点神秘的编译器消息。

  sealed trait Vector[A] {

    type ThisButType[B] <: Vector[B]

    def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A,B]]
  }

  case class Term[A]() extends Vector[A] {
   
    type ThisButType[B] = Term[B]
   
    def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A,B]] = Term[Tuple2[A,B]]()
  
  }

  case class Component[A,T <: Vector[A]](value: A,tail: T) extends Vector[A]{

    type ThisButType[B] = Component[B,T#ThisButType[B]]

    def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A,B]] =
      Component[Tuple2[A,B],T#ThisButType[Tuple2[A,B]]]((value,other.value),tail.zip(other.tail))
  }

我得到的错误是:

 type mismatch;
   found   : other.tail.type (with underlying type T#ThisButType[B])
   required: Component.this.tail.ThisButType[B]

在这种情况下,编译器为什么不能弄清楚T应该和Component.this.tail一样?

解决方法

假设确实如此:

// applying some other minor changes...
sealed trait Vector[A] {
    type ThisButType[B] <: Vector[B]
    def zip[B](other: ThisButType[B]): ThisButType[(A,B)]
}
case class Term[A]() extends Vector[A] {
    override type ThisButType[B] = Term[B]
    override def zip[B](other: Term[B]): Term[(A,B)] = Term()
}
case class Component[A,T <: Vector[A]](value: A,tail: T) extends Vector[A] {
    override type ThisButType[B] = Component[B,T#ThisButType[B]]
    override def zip[B](other: Component[B,T#ThisButType[B]]): Component[(A,B),T#ThisButType[(A,B)]] =
        Component((value,other.value),tail.zip(other.tail.asInstanceOf[tail.ThisButType[B]]))
}

但是然后...

val zero = Term[Unit]()
val zero0: Vector[Unit]#ThisButType[Int] = Term[Int](): zero.ThisButType[Int] // the mystical double type ascription!
val two = Component((),Component((),Term[Unit]()): Vector[Unit])
two.zip(Component(0,zero0)) // ClassCastException!

因此,关于您的代码的某些错误实际上是类型错误的,编译器正确地将其视为错误。具体来说,代码中的T#ThisButType[B]tail.ThisButType[B]完全不同 ,因为tail不必是确切的类型T但可以是某些子类型。在这种情况下,T#ThisButType[B]可以包含tail.ThisButType[B]不包含的值,这意味着您无法将前一个(other.tail)传递给想要的函数(tail.zip)后者。

故事的道德:类型投射是邪恶的,应该避免。您在那里拥有完美的 value tail: T;只是从中投射。

// applying some more minor changes...
sealed trait Vector[+A] {
    type ThisButType[+B] <: Vector[B]
    def zip[B](other: ThisButType[B]): ThisButType[(A,B)]
}
case object Term extends Vector[Nothing] {
    override type ThisButType[+B] = Term.type
    override def zip[B](other: Term.type): Term.type = Term
}
case class Component[+A,+T <: Vector[A]](value: A,tail: T) extends Vector[A] {
    override type ThisButType[+B] = Component[B,tail.ThisButType[B]]
    override def zip[B](other: Component[B,tail.ThisButType[B]]): Component[(A,tail.ThisButType[(A,tail.zip(other.tail))
}

之前的示例不再起作用:

val zero: Vector[Unit]#ThisButType[Int] = Term: Term.ThisButType[Int]
val two = Component((),Term): Vector[Unit])
two.zip(Component(0,zero)) // fails: don't know that zero: two.tail.ThisButType[Int]

现在代码正确了。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...