所以我在 Kotlin 中尝试了泛型。假设我有一个典型Box
类型:
class Box<T>
*
现在,我明白,当我不关心任何包含该类型的方法或属性时,我可以在函数中使用投影T
。
因此,例如,如果有一个takeBox1
带有盒子并且根本不使用 T 的,我可以将其声明为:
fun takeBox1(box: Box<*>) {}
然后如果我有一个特定的T
盒子我可以提供因为takeBox1
并不关心T
它是什么:
fun <T> giveBox1(box: Box<T>) {
takeBox1(box)
}
然而,当我有一个双层包装的盒子时,情况就变得很奇怪了,即takeBox2
接受的Box<Box<*>>
,它不接受特定的Box<Box<T>>
:
fun takeBox2(box: Box<Box<*>>) {}
fun <T> giveBox2(box: Box<Box<T>>) {
takeBox2(box) // compiler error!
}
这很奇怪,如果它可以接受任何东西的盒子中的盒子,为什么它不能接受某物的盒子中的盒子?请注意,我在实现中根本没有使用 T - 也许我只是在做某事box.size
。
经过更多测试后,如果我将外部框声明为out
,它确实可以工作,但前提是外部框Box
是OutBox
;所以:
class OutBox<out T>
fun takeOutBox(box: OutBox<Box<*>>) {}
fun <T> giveOutBox2(box: OutBox<Box<T>>) {
takeOutBox(box) // works
}
fun takeBoxOut(box: Box<OutBox<*>>) {}
fun <T> giveBoxOut2(box: Box<OutBox<T>>) {
takeBoxOut(box) // does not compile
}
fun takeOutBoxOut(box: OutBox<OutBox<*>>) {}
fun <T> giveOutBoxOut2(box: OutBox<OutBox<T>>) {
takeOutBoxOut(box) // works
}
如果我这样做了in
,它在任何情况下都根本不起作用。
我读过Kotlin 泛型的文档,特别是关于in
、out
和星投影 ( *
) 的文档,我认为我已经很好地掌握了它,但我似乎无法证明/解释这种特殊行为。我也读过关于 行为的其他答案,*
但我不明白为什么双重包装的Box
行为与单数 的行为不同Box
。