Kotlin: даже если класс имеет обнуляемый универсальный c параметр типа E, назначение не выполняется - PullRequest
0 голосов
/ 01 апреля 2020

Я борюсь с обнуляемыми и не обнуляемыми типами. Есть две ошибки. Я определил класс, который реализует концепцию «Очередь» следующим образом, пытаясь сделать его Generi c Parametri c Type обнуляемым, и здесь есть первая ошибка:

class QueueLightweight<T: Any?> { //: Queue<T?> removed because of Java clashes, but it's another question
        protected var size = 0
        protected var first: NodeQLW<T>? = null
        protected var last: NodeQLW<T>? = null

        protected class NodeQLW<E>(var item: E) {
            var next: NodeQLW<E>? = null
        }

        ....

        fun iterator(): Iterator<T> {
            return IteratorQLW(this)
        }

        ....

        fun add(e: T?): Boolean {
            val n: NodeQLW<T>
            n = NodeQLW(e) // <--- first error: 
            // "type inference failed: required: QueueLightweight.NodeQLW<T> , found: QueueLightweight.NodeQLW<T?> "
            if (size == 0) {
                last = n
                first = last
                size = 1
            } else {
                last!!.next = n
                last = n
                size++
            }
            return true
        }
    }

Затем я определил Iterator подкласс следующим образом, и в выделенной строке (стрелкой) есть ошибка.

protected class IteratorQLW<E: Any?>(var q: QueueLightweight<E>) :
Iterator<E> {
var n: NodeQLW<E>?
init {
    n = q.first
}

override fun hasNext(): Boolean {
    return n != null
}

override fun next(): E {
    var e: E
    e = null // <--- error here: null cannot be a value of a non-null type E
    if (n != null) {
        e = n!!.item
        n = n!!.next
    }
    return e
}

}

Я не понимаю, как исправить эти ошибки.

Ответы [ 2 ]

2 голосов
/ 01 апреля 2020

Тип допускает nullable по умолчанию, поэтому ваше определение типа класса может быть просто <T>, а не <T: Any?>. Тип generi c может быть назначен как ненулевой, когда используется класс (например, использование QueueLightweight<String> вместо QueueLightweight<String?>), поэтому вы должны обращаться с ним, как если бы вы работали с тип generi c внутри класса.

Это источник вашей первой проблемы. Ваш NodeQLE ожидает, возможно, ненулевой параметр для своего конструктора, но вы заставляете его иметь значение null. Ваш метод add должен принимать параметр T, а не принудительный T?.

Тогда в В своем итераторе вы объявляете переменную как (возможно) ненулевую E, но присваиваете ей значение null. Вам нужно сделать переменную обнуляемой. Так как он может вернуть ноль, даже если E не обнуляем, вы должны вызвать исключение, если следующего значения нет. Но это можно упростить, изменив ветвление, поэтому метод должен выглядеть следующим образом:

override fun next(): E {
    n?.let {
        n = it.next
        return it.item
    }
    throw NoSuchElementException()
}
1 голос
/ 01 апреля 2020

Необнуляемые типы - это подтипы соответствующих обнуляемых типов. Например, любой String является String? и, следовательно, String является подтипом String?. Таким образом, любой тип вообще, включая ненулевые типы, является подтипом Any?, а E: Any? bound не заставляет E быть обнуляемым (и может быть удален).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...