使用一个对象来实现一个空List的错误

我试图重写列表接口作为学习功能编程Kotlin的练习,但我无法弄清楚为什么我得到一个错误,当我试图让一个对象作为空的列表,在Kotlin标准库中不会发生。 在我的代码中,见下面,我想使用NIL作为单例空列表,使用list()作为函数返回它。 但是,这会在类型为“必需列表”的函数上生成类型不匹配错误。找到NIL“

interface List<A> { val empty: Boolean val head: A val tail: List<A> fun cons(a: A): List<A> = Cons(a, this) } object NIL : List<Nothing> { override val empty: Boolean = true override val head: Nothing get() = throw IllegalStateException("head called on empty list") override val tail: List<Nothing> get() = throw IllegalStateException("tail called on empty list") } private class Cons<A>(override val head: A, override val tail: List<A>) : List<A> { override val empty: Boolean = false } fun <A> list(): List<A> = NIL // Type mismatch. Required: List<A>. Found: NIL fun <A> list(vararg a: A): List<A> { var n = list<A>() for (e in a.reversed()) { n = Cons(e, n) } return n } 

在标准库中,这个错误不会发生,正如您可以在Collections.kt的EmptyList中看到的一样 。 我做错了什么,或者我错过了一些让后者成为可能的概念,而前者不是?

评估提出的解决方案

在所提出的三种解决方案中,唯一允许通过下面的测试代码的是使用匿名对象的 ,而其他的则抛出异常java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Void

 assertEquals("a", list<String>().cons("a").head) 

但是,如果将NIL更改为NIL : List<Any?> ,则解决方案NIL as List<A>工作没有任何问题。

您可以通过as关键字将List<Nothing> List<A>转换为List<A> ,例如:

 fun <A> list(): List<A> = NIL as List<A>; 

如果你想压制编译器警告,你可以使用@Suppress注解来注释这个函数,例如:

 @Suppress("UNCHECKED_CAST") fun <A> list(): List<A> = NIL as List<A>; 

或者如果你不喜欢这种方式,你可以用一个匿名的对象来代替,例如:

 fun <A> list(): List<A> = object : List<A> { override val empty: Boolean = true override val head: A get() = throw IllegalStateException("head called on empty list") override val tail: List<A> get() = throw IllegalStateException("tail called on empty list") }; 

通用接口应该是<out A>而不是<A>

另外,IntelliJ Idea在这种情况下使用泛型时会显示一个警告。