在his course on 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())))
}
}
令我困扰的是最后一行new Nil()
中Nil类的实例化。
如何将Nil定义为object
而不是Scala类,并使其符合参数化类型List [T]?
我想在下面的代码行中引用Nil对象(没有实例化),并使其具有正确的类型
new Cons("A", new Cons("B", new Cons("C", Nil)))
答案 0 :(得分:3)
在实际的Scala库(List.scala)中,这是如何完成的,
case object Nil extends List[Nothing] { ...
可能在课堂上他想避免引入Nothing
,type at the bottom of Scala's type lattice。
答案 1 :(得分:3)
鉴于列表的trait List[T]
定义,您无法做到。该定义意味着每个Nil
都需要一个不同的T
,因为对于每个T1
和T2
,不相同,List[T1]
与{{1}不兼容}}。由于List[T2]
必须“成为”Nil
,因此您选择的任何List[Tx]
都将与所有其他Tx
不兼容。
要解决这个问题,你需要协方差,iirc,稍后会解释几个教训。
答案 2 :(得分: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安装进行编译。应用程序实现“主”,因此您必须覆盖它或(因为应用程序的意图)将其删除。
请注意,您需要List
和Cons
是协变的(例如List[+T]
),这基本上意味着对于T的子类型U,它还认为List[U]
是一个List[T]
的子类型,扩展名为List [Nothing]是列表的子类型。