将不可空的字符串数组作为可空的字符串数组传递
我有一个函数,在一个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中的数组是不变的 ,这意味着对于任何不同的A
和B
, Array<A>
和Array<B>
都不是彼此的子类型,包括String
和String?
,而且他们不能被分配和通过作为论点在彼此的地方。
使用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 T
而String
是String
的子集String?
在Kotlin中,所以Array<String?>
在Kotlin中扩展了Array<String?>
。 正如你所看到的,继承图的左边是上界的通配符继承。