4

他的 Coursera 课程中,Martin Odesrky 教授在关于多态性和参数化类的讲座中以链表为例:

package week4

trait List[T] {
  def isEmpty: Boolean
  def head: T
  def tail: List[T]
}
class Cons[T](val head: T, val tail: List[T]) extends List[T] {
  def isEmpty = false
}
class Nil[T] extends List[T] {
  def isEmpty = true
  def head = throw new NoSuchElementException("Nil.head")
  def tail = throw new NoSuchElementException("Nil.tail")
}
object Main extends App {
  def main(args: Array[String]) {
    val lst = new Cons("A", new Cons("B", new Cons("C", new Nil())))
  }
}

困扰我的是最后几行中类 Nil 的实例化,new Nil().

如何将 Nil 定义为 anobject而不是 Scala 类,并使其符合参数化类型 List[T] ?

我想在下面的代码行(没有实例化)中引用对象 Nil,并使其具有正确的类型

new Cons("A", new Cons("B", new Cons("C", Nil)))
4

3 回答 3

3

在实际的 Scala 库(List.scala)中,它是如何完成的,

case object Nil extends List[Nothing] { ...

可能在他想避免引入的类中Nothing,这是Scala 类型 lattice 底部的类型

于 2013-04-14T16:35:49.890 回答
3

鉴于trait List[T]列表的定义,您不能这样做。该定义意味着您需要一个 distinct Nilfor each T,因为for each T1andT2不完全相同,List[T1]与 不兼容List[T2]。由于Nilmust "be a" List[Tx]Tx因此您选择的任何一个都将与其他所有不兼容。

为了解决这个问题,您需要协方差,iirc 稍后会解释几节课。

于 2013-04-14T16:57:36.167 回答
2

以下是 Kipton 的建议和我自己的建议:

trait List[+T] {
  def isEmpty: Boolean
  def head: T
  def tail: List[T]
}
class Cons[+T](val head: T, val tail: List[T]) extends List[T] {
  def isEmpty = false
}
case object Nil extends List[Nothing] {
  def isEmpty = true
  def head = throw new NoSuchElementException("Nil.head")
  def tail = throw new NoSuchElementException("Nil.tail")
}
object ListTest {
  def main(args: Array[String]) {
    val lst = new Cons("A", new Cons("B", new Cons("C", Nil)))
  }
}

顺便说一句,我的 Scala 安装无法编译您的代码。App 实现“main”,因此您必须覆盖它或(正如 App 的意图)将其排除在外。

请注意,您需要List并且Cons是协变的(例如List[+T]),这基本上意味着对于 T 的子类型 U,它还认为它List[U]是子类型,List[T]并且通过扩展 List[Nothing] 是列表的子类型。

于 2013-04-14T16:45:49.560 回答