Kotlin 类型不匹配:需要数组 <Int?>?但发现 Array<Int>
Kotlin type mismatch: required Array<Int?>? but found Array<Int>
这是我的 Foo
数据 class 定义
data class Foo(
var fooArg: Array<Int?>? = null,
)
这是对它的调用:
val bar: Array<Int> = arrayOf(1,2,3)
val foo = Foo(fooArg = bar)
但是这给出了一个错误type mismatch: required Array<Int?>? but found Array<Int>
我很困惑,它需要一个可为 null 的类型,而我为它提供了一个非 null 值,该类型怎么不匹配?
您将 bar
声明为 Array<Int>
。非空类型与可空类型不兼容*。将其更改为 Array<Int?>
它将起作用:
val bar: Array<Int?> = arrayOf(1,2,3)
val foo = Foo(fooArg = bar)
或者:
val bar = arrayOf<Int?>(1, 2, 3)
*我认为正确的说法是数组在类型参数上是不变的。但每次我试图正确理解它时,我都会迷路。
Adam 的回答涵盖了解决方案,但也值得一提的是为什么您所做的没有 工作。 Java 使用调用站点差异注释,这与现有的大多数其他语言不同。 Kotlin 采用更传统的方法,即使用声明站点差异注释。这意味着,当声明一个接受泛型参数的 class 时,class 的作者决定它在子类型方面的行为方式。
现在,Int
是 Int?
的子类型。也就是说,每个 Int
都是一个 Int?
,但反之则不然。问题是:Array<Int>
是 Array<Int?>
的子类型吗?好吧,List<T>
等协变类型保留子类型,因此 List<Int>
实际上是 List<Int?>
的子类型。如果您将问题中的示例替换为列表而不是数组,则一切正常。
另一方面,Array<T>
是不变类型。我们既可以读取数组也可以写入数组,因此向上转换或向下转换类型参数是不安全的。如果可以的话,下面的内容将进行类型检查。
// Doesn't compile, for good reason
val myHealthyArray: Array<Int> = arrayOf(1);
val myScaryNullableArray: Array<Int?> = myHealthyArray;
myScaryNullableArray[0] = null;
现在我完全无辜的 myHealthyArray
变量中有一个 null
类型 Array<Int>
无法解释。这与 Kotlin 所代表的一切背道而驰,因此原则上是不允许的。
如果你只打算将此数据结构用于阅读,而不是写作,请考虑使用 List<T>
或协变的东西,它能更好地描述类型你的功能,还允许子类型化关系更充分地工作。
这是我的 Foo
数据 class 定义
data class Foo(
var fooArg: Array<Int?>? = null,
)
这是对它的调用:
val bar: Array<Int> = arrayOf(1,2,3)
val foo = Foo(fooArg = bar)
但是这给出了一个错误type mismatch: required Array<Int?>? but found Array<Int>
我很困惑,它需要一个可为 null 的类型,而我为它提供了一个非 null 值,该类型怎么不匹配?
您将 bar
声明为 Array<Int>
。非空类型与可空类型不兼容*。将其更改为 Array<Int?>
它将起作用:
val bar: Array<Int?> = arrayOf(1,2,3)
val foo = Foo(fooArg = bar)
或者:
val bar = arrayOf<Int?>(1, 2, 3)
*我认为正确的说法是数组在类型参数上是不变的。但每次我试图正确理解它时,我都会迷路。
Adam 的回答涵盖了解决方案,但也值得一提的是为什么您所做的没有 工作。 Java 使用调用站点差异注释,这与现有的大多数其他语言不同。 Kotlin 采用更传统的方法,即使用声明站点差异注释。这意味着,当声明一个接受泛型参数的 class 时,class 的作者决定它在子类型方面的行为方式。
现在,Int
是 Int?
的子类型。也就是说,每个 Int
都是一个 Int?
,但反之则不然。问题是:Array<Int>
是 Array<Int?>
的子类型吗?好吧,List<T>
等协变类型保留子类型,因此 List<Int>
实际上是 List<Int?>
的子类型。如果您将问题中的示例替换为列表而不是数组,则一切正常。
另一方面,Array<T>
是不变类型。我们既可以读取数组也可以写入数组,因此向上转换或向下转换类型参数是不安全的。如果可以的话,下面的内容将进行类型检查。
// Doesn't compile, for good reason
val myHealthyArray: Array<Int> = arrayOf(1);
val myScaryNullableArray: Array<Int?> = myHealthyArray;
myScaryNullableArray[0] = null;
现在我完全无辜的 myHealthyArray
变量中有一个 null
类型 Array<Int>
无法解释。这与 Kotlin 所代表的一切背道而驰,因此原则上是不允许的。
如果你只打算将此数据结构用于阅读,而不是写作,请考虑使用 List<T>
或协变的东西,它能更好地描述类型你的功能,还允许子类型化关系更充分地工作。