Kotlin:即使 class 具有可为空的泛型参数类型 E,赋值也会失败
Kotlin: Even if the class has a nullable generic parameter type E, assignement fails
我正在努力处理可空类型和不可空类型。有两个错误。
我定义了一个实现 "Queue" 概念的 class,如下所示,试图使其通用参数类型可为空,这里出现第一个错误:
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 subclass 如下,在突出显示的行(用箭头表示)中,有错误。
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
}
}
我不明白如何修复这些错误。
该类型默认允许为空,因此您的 class 类型定义只能是 <T>
,而不是 <T: Any?>
。当使用 class 时(例如使用 QueueLightweight<String>
而不是 QueueLightweight<String?>
),可以将泛型类型指定为不可空的,因此您必须将其视为不可空的当您在 class 中使用泛型类型时。
这是您第一个问题的根源。你的 NodeQLE 期望它的构造函数有一个可能不可为 null 的参数,但你强制它是 null.Your add
方法应该采用 T
参数,而不是强制执行 T?
。
然后在迭代器中将一个变量声明为(可能)不可为空 E
,但为其分配一个空值。您需要使变量可为空。由于即使 E 不可为空,它也可以 return null,如果没有下一个值,则必须抛出异常。但这可以通过改变分支来简化,所以方法应该是这样的:
override fun next(): E {
n?.let {
n = it.next
return it.item
}
throw NoSuchElementException()
}
不可空类型是相应可空类型的子类型。例如。任何 String
都是 String?
,因此 String
是 String?
的子类型。因此,任何类型,包括不可为空的类型,都是 Any?
的子类型,并且 E: Any?
绑定不会强制 E
为可空(并且可以删除)。
我正在努力处理可空类型和不可空类型。有两个错误。 我定义了一个实现 "Queue" 概念的 class,如下所示,试图使其通用参数类型可为空,这里出现第一个错误:
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 subclass 如下,在突出显示的行(用箭头表示)中,有错误。
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
}
}
我不明白如何修复这些错误。
该类型默认允许为空,因此您的 class 类型定义只能是 <T>
,而不是 <T: Any?>
。当使用 class 时(例如使用 QueueLightweight<String>
而不是 QueueLightweight<String?>
),可以将泛型类型指定为不可空的,因此您必须将其视为不可空的当您在 class 中使用泛型类型时。
这是您第一个问题的根源。你的 NodeQLE 期望它的构造函数有一个可能不可为 null 的参数,但你强制它是 null.Your add
方法应该采用 T
参数,而不是强制执行 T?
。
然后在迭代器中将一个变量声明为(可能)不可为空 E
,但为其分配一个空值。您需要使变量可为空。由于即使 E 不可为空,它也可以 return null,如果没有下一个值,则必须抛出异常。但这可以通过改变分支来简化,所以方法应该是这样的:
override fun next(): E {
n?.let {
n = it.next
return it.item
}
throw NoSuchElementException()
}
不可空类型是相应可空类型的子类型。例如。任何 String
都是 String?
,因此 String
是 String?
的子类型。因此,任何类型,包括不可为空的类型,都是 Any?
的子类型,并且 E: Any?
绑定不会强制 E
为可空(并且可以删除)。