了解 Kotlin 泛型中初始化和赋值之间的区别



我正在阅读"Kotlin 编程 - 大书牧场指南"一书中有关 Kotlin 中进出关键字的部分。我来自一个C++背景,初始化和赋值是两个非常不同的概念。书中的以下代码片段(略有修改(让我承认。

代码如下:

class Barrel<out T>(val item:T)
open class Loot(val value: Int)
class Fedora(val name:String, value:Int) : Loot(value)
public fun main(){
var fedoraBarrel: Barrel<Fedora> = Barrel(Fedora("a generic-looking fedora", 15))
var lootBarrel: Barrel<Loot> = fedoraBarrel
lootBarrel = fedoraBarrel
val myFedora: Fedora = lootBarrel.item
}

在这里,当我注释掉这一行时

lootBarrel = fedoraBarrel

我在尝试从桶中检索Fedora项目的后续行上收到以下错误,错误是

Error:(27, 28) Kotlin: Type mismatch: inferred type is Loot but Fedora was expected

将 fedoraBarrel 分配给 lootBarrel 与使用 fedoraBarrel 初始化 lootBarrel 有何不同。为什么我需要这条线

lootBarrel = fedoraBarrel 

要编译此代码?

为什么这条线var lootBarrel: Barrel<Loot> = fedoraBarrel没有意义?

它不是没有意义的,恰恰相反;你明确要求更通用的类型, 编译器合理地假设你真的希望lootBarrel有类型Barrel<Loot>,所以lootBarrel.item有类型Loot,而不是Fedora

lootBarrel = fedoraBarrel 

编译器看到它被分配了一个类型为Barrel<Fedora>的值,因此可以在本地将其视为具有该类型,直到它被更改。

不重新分配它能工作吗?是的。在 https://youtrack.jetbrains.com/issue/KT-13663 讨论,目前的结论是

我认为不可能在所有情况下合理地实现此请求,我们需要设计一种棘手的算法来使其至少在大多数情况下起作用。

在您的情况下,最后的评论给出了解决方法

var lootBarrel: Barrel<Loot>
lootBarrel = fedoraBarrel
val myFedora: Fedora = lootBarrel.item

(注意这是初始化,不是赋值(

让我们将您的情况简化为以下代码:

var a: Number = 0
a + 1 // Raises an error, class Number does not have `plus` function
a = 0
a + 1 // Works fine

初始化变量时 (var a: Number = 0( 编译器将a的类型设置为Number,而不考虑用作初始值的表达式类型(它不会将a转换为Int,因为您显式指定了类型(。

当您编写a = 0时,会发生智能转换,因此您可以像使用Int一样使用a,直到再次更改a

最新更新