所以我在 Kotlin 中尝试泛型。假设我有一个典型的
Box
类型:
class Box<T>
现在,我知道当我不关心包含
*
类型的任何方法或属性时,我可以在函数中使用 T
投影。
例如,如果 a 有一个
takeBox1
需要一个盒子并且根本不使用 T,我可以将其声明为:
fun takeBox1(box: Box<*>) {}
然后,如果我有一个特定的
T
盒子,我可以提供,因为takeBox1
不关心它是什么:T
但是,当我有一个双层包装的盒子时,即一个带有
fun <T> giveBox1(box: Box<T>) {
takeBox1(box)
}
的
takeBox2
,它不接受特定的 Box<Box<*>>
:Box<Box<T>>
这很奇怪,如果它可以接受一盒又一盒的东西,为什么它不能接受一盒又一盒的东西呢?请注意,我在实现中根本没有使用 T - 也许我只是在做
fun takeBox2(box: Box<Box<*>>) {}
fun <T> giveBox2(box: Box<Box<T>>) {
takeBox2(box) // compiler error!
}
或其他事情。
经过更多测试,如果我将外框声明为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
}
,它在任何情况下都不起作用。
我已经阅读了关于 Kotlin 泛型的文档,特别是关于 in
、
in
和星形投影 (out
),我认为我已经很好地掌握了它,但我似乎无法证明/解释这个特殊的行为。我还阅读了有关 *
行为的其他答案,但我不明白为什么双层包装的 *
的行为与单数 Box
的行为不同。Box
或其他事情。
编译器不关心你用盒子做什么。它只查看类型。这些类型描述了你可以用一个值做的所有可能的事情,在这种情况下,这些类型不能确保“我只是在做
box.size
或其他事情”。
box.size
的问题在于它允许您
输入一个
Box<Box<*>>
,其中Box<U>
是任何类型,不一定是U
中声明的T
。假设giveBox2
是
Box
如果您的代码被允许编译,则可以将
class Box<T>(var boxed: T)
传递给
Box<Box<String>>
,并且 giveBox2
可以这样做:takeBox2
之后,您最终会得到一个
box.boxed = Box(100)
类型的变量,它实际上包含一个
Box<Box<String>>
。“但我实际上不会做Box<Box<Int>>
这样的事情!”你可能会说。然后你应该告诉编译器,通过将
box.boxed = Box(100)
的参数类型更改为 takeBox2
之类的东西。如果您只想在外部Box<out Box<*>>
上使用
size
,那么您可以更进一步,将其更改为Box
。