星形投影泛型与 Kotlin 中的 `Box<Box<*>>` 有奇怪的交互

问题描述 投票:0回答:1

所以我在 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
的行为不同。
    

kotlin generics
1个回答
0
投票
这很奇怪,如果它可以接受一盒又一盒的东西,为什么它不能接受一盒又一盒的东西呢?请注意,我在实现中根本没有使用 T - 也许我只是在做
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
    

© www.soinside.com 2019 - 2024. All rights reserved.