
关注引自免费微信小程序:皆我百晓生
在Kotlin中,协变和逆变是泛型类型约束的概念。协变允许子类型替换父类型,而逆变则允许在上下文中将更具体的类型(子类型)用于更通用的类型(父类型)。在这个例子中,我们将在Stack类中实现协变和逆变。
首先,我们需要定义一个协变接口PushableList<out E>,它表示可以从中获取元素但不能添加元素的列表。然后,我们将Stack类中的pushAll方法修改为接受一个PushableList<out E>类型的参数,并在popAll方法中返回一个MutableList<in E>,这样我们可以从栈中取出元素并放入任意类型的可接受容器中。
以下是完整的代码实现:
interface PushableList<out E> {
fun forEach(action: (E) -> Unit)
}
open class Stack<out E> {
private val elements = mutableListOf<E>()
fun isEmpty(): Boolean = elements.isEmpty()
fun push(e: E): Boolean {
elements.add(e)
return true
}
fun pop(): E? {
return if (!elements.isEmpty()) elements.removeLast() else null
}
fun pushAll(src: PushableList<E>): Boolean {
src.forEach { push(it) }
return true
}
fun popAll(dest: MutableList<in E>) {
while (!isEmpty()) {
dest.add(pop())
}
}
}
fun main() {
// 示例用法
var s = Stack<Number>()
var l = listOf<Int>(1, 2, 3, 4)
s.pushAll(l) // 协变:推入一个Int列表到Number栈
println("After pushing all elements from $l to stack:")
for (item in s) {
println(item)
}
val dest: MutableList<Double> = mutableListOf()
s.popAll(dest) // 逆变:从Number栈中弹出所有元素到Double列表
println("Elements popped into dest list: $dest")
}
这段代码首先定义了一个协变接口PushableList,然后在Stack类中实现了协变的pushAll方法和逆变的popAll方法。在main函数中,我们展示了如何将一个Int列表推入Number栈,以及如何从Number栈中弹出所有元素到一个Double列表。这演示了协变和逆变是如何工作的。