将不可空的字符串数组作为可空的字符串数组传递

我有一个函数,在一个Array<String?>

 fun doStuff(words: Array<String?>) { // ... } 

有一种方法,我可以传递一个Array<String>到这个函数? 原来是编译器给我一个“类型不匹配”的错误。

 private val SOME_WORDS = arrayOf("I", "want", "to", "use", "these") doStuff(SOME_WORDS) // throws a type-mismatch error 

最好,我想避免使SOME_WORDS arrayOf<String?>(...)如果可能的话。

使用out -projected Array<out String?>

 fun doStuff(words: Array<out String?>) { /* ... */ } 

Kotlin中的数组是不变的 ,这意味着对于任何不同的ABArray<A>Array<B>都不是彼此的子类型,包括StringString? ,而且他们不能被分配和通过作为论点在彼此的地方。

使用out -projection Array<out String?>使函数不仅接受Array<String?>而且还使用String?子类型的String? 。 基本上,因为类型是final ,所以只有一个这样的子类型,它是String (非空的,没有? )。

类型方差图

图片来自: Kotlin类型层次的旋风之旅 )

所以,函数也会接受Arrray<String> 。 但是你不能将可为空的值放到数组中(这就是投影的工作方式),所以类型安全性(和空安全性)被保留。

这里的问题是不一致的String是它的可空的朋友String?的子类型String? 但在Kotlin中,这并不意味着Array<String>Array<String?>的子类型,因为数组是不变的 。 (在Java中,情况并非如此,数组默认是协变的)

如果你有一个像你的函数那样需要Array<String?>类型的参数,那么你只能传递Array<String?> ,因此Array<String>是不可能的! 如果你想让你的方法也可以处理这些数组,可以这样做:

 fun doStuff(words: Array<out String?>) { // ... } 

这使得Array<String?>的数组words covariant和子类型被允许传递。

请注意,只有像get()这样的函数get()访问这些“超出预期”的数组。 参数words据说是一个String?生产者 String?

如果你想了解更多关于它,看看官方文档 🙂

您应该使用out类型投影,因为泛型类型Array<String> Array<String?>在Kotlin中扩展Any而不是Array<String?> ,例如:

 // v--- use out type projection here fun doStuff(words: Array<out String?>) { // ... } 

通用继承

当在Kotlin中使用out类型的投影就像是上界的通配符 ? extends T 用Java ? extends TStringString的子集String? 在Kotlin中,所以Array<String?>在Kotlin中扩展了Array<String?> 。 正如你所看到的,继承图的左边是上界的通配符继承。

上界有界的通配符