应用类型投影时,类型参数如何变成 Nothing、Any?或类型界限等?
我在 Kotlin 中发现了一些对我来说一直很直观的东西,但我最近意识到我无法解释其中的底层细节。
考虑一下以下代码中 x.returnT
的返回类型以及 consumeT
和 aMoreComplicatedCase
的参数类型:
val x: Foo<*> = TODO()
class Foo<T> {
fun returnT(): T = TODO()
fun consumeT(t: T) {}
fun aMoreComplicatedCase(func: (T) -> T) {}
}
IntelliJ 告诉我x.returnT
返回 Any?
,consumeT
接受 Nothing
,aMoreComplicatedCase
接受(有吗?)->什么都没有。
使用规范,我们知道*
大致意味着同时 out Any?
和 in Nothing
,并应用 PECS (或者这应该在 Kotlin 中称为 POCI,因为生产者 out
消费者 in< /代码>),我们知道
x
是 Any?
的生产者,但什么也没有的消费者。
更直观的解释是,*
的意思是“我们对 Foo
的 <>
中的内容一无所知”,并且因此,当然 returnT
可以返回任何内容,甚至可以为 null 的内容。同样,当然 consumeT
不能接受任何东西 - 它需要 T
,具体是什么我们不知道。
类似的参数可以应用于 out SomeType
或 in SomeType
的情况。
我陷入困境的地方我
已经用Java编程很长时间了,我根本没想到会出现这样的结果。我期望类似于 IntelliJ 对类似 Java 代码所说的内容:
public class Main {
public static void main(String[] args) {
Foo<?> foo = new Foo<>();
}
}
class Foo<T> {
public T returnT() { return null; }
public void consumeT(T t) { }
public void aMoreComplicatedCase(Function<T, T> func) { }
}
IntelliJ 说 x.returnT
返回 ?
的捕获,consumeT
需要?
的捕获,以及 aMoreComplicatedCase
接受 Function
:
我查看了 Kotlin 规范,发现 Kotlin 也有 捕获类型,它们是具有一定边界的新类型变量。 那么 Nothing
和 Any?
从何而来?或者在使用 in SomeType
作为投影的情况下, consumeT
将采用 SomeType
代替。 为什么它是 SomeType
,而不是以 SomeType
作为其子类型的捕获类型? 毕竟,规范在类型捕获部分中说:
- 对于 Ai 中的逆变类型参数 Ai,如果 Fi 是协变类型参数,则 Ki 是格式错误的类型。否则,Ki :>艾。
- 对于双变量类型参数
⋆
,kotlin.Nothing
<: Ki <:kotlin.Any?
我猜测之后会发生其他事情类型捕获?这个过程叫什么?或者这里是否有一个完全不同的过程,不是类型捕获?
(我猜这也有可能只是“当类型是捕获类型时,IntelliJ/kotlinc 使用什么字符串表示形式进行显示”的问题,与类型系统本身无关......)
I found something in Kotlin that had always been intuitive to me, but I recently realised I can't explain the low level details of this.
Consider what the return type of x.returnT
, and the parameter types of consumeT
and aMoreComplicatedCase
would be in the below code:
val x: Foo<*> = TODO()
class Foo<T> {
fun returnT(): T = TODO()
fun consumeT(t: T) {}
fun aMoreComplicatedCase(func: (T) -> T) {}
}
IntelliJ tells me that x.returnT
returns Any?
, consumeT
takes Nothing
, and aMoreComplicatedCase
takes (Any?) -> Nothing
.
Using the spec, we know that *
roughly means out Any?
and in Nothing
at the same time, and applying PECS (Or maybe this should be called POCI in Kotlin since producer out
consumer in
), we know x
is a producer of Any?
and a consumer of nothing.
An even more intuitive explanation is that *
means "we know nothing about what goes in the <>
of Foo
at all", and because of that, of course returnT
can return anything, even nullable things. Similarly, of course consumeT
can't take anything - it takes T
, the exact thing we don't know.
Similar arguments can be applied to cases where it is out SomeType
or in SomeType
.
Where I am stuck
Having been programming in Java for a long time, I did not expect this result at all. I expected something similar to what IntelliJ would say for the similar Java code:
public class Main {
public static void main(String[] args) {
Foo<?> foo = new Foo<>();
}
}
class Foo<T> {
public T returnT() { return null; }
public void consumeT(T t) { }
public void aMoreComplicatedCase(Function<T, T> func) { }
}
IntelliJ says that x.returnT
returns a capture of ?
, consumeT
takes a capture of ?
, and aMoreComplicatedCase
takes Function<capture of ?, capture of ?>
:
I looked around the Kotlin spec and found that Kotlin also have captured types, which are fresh type variables with certain bounds. So where does Nothing
and Any?
come from? Or in the case of using in SomeType
as the projection, consumeT
will take a SomeType
instead. Why is it SomeType
, but not a capture type with SomeType
as its subtype? After all, the spec says in the type capturing section:
- For a contravariant type argument Ai
in Ai
, if Fi is a covariant type parameter, Ki is an ill-formed type. Otherwise, Ki :> Ai.- For a bivariant type argument
⋆
,kotlin.Nothing
<: Ki <:kotlin.Any?
I'm guessing something else happens after type capturing? What is that process called? Or is there a totally different process that is not type capturing going on here?
(I guess there is also the possibility that this is just a matter of "what string representation IntelliJ/kotlinc uses for display, when the type is a captured type" and has nothing to do with the type system itself...)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论