Intereting Posts

Ошибка при использовании объекта для реализации пустого списка

Я пытаюсь переписать интерфейс List как упражнение для изучения функционального программирования в 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 } 

В стандартной библиотеке эта ошибка не возникает, как вы можете видеть в EmptyList в Collections.kt . Я что-то делаю неправильно, или я пропускаю некоторые концепции, которые делают последнее возможным, а первое – нет?

Оценка предлагаемых решений

Из трех предложенных решений единственное, что позволяет передать тестовый код ниже, – это тот, который использует анонимный объект , в то время как другие генерируют исключение 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> работает без проблем.

Solutions Collecting From Web of "Ошибка при использовании объекта для реализации пустого списка"

вы можете использовать List<Nothing> для List<A> явно as ключевое слово, например:

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

Если вы хотите подавить предупреждения компилятора, вы можете аннотировать функцию с @Suppress аннотации @Suppress , например:

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

ИЛИ, если вам не нравится этот способ, вы можете использовать анонимный объект в funtion, например:

 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 показывает предупреждение, когда вы используете генерики без дисперсии в таких случаях.