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

时间:2017-08-24 16:11:52

标签: kotlin

我有一个接受Array<String?>

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

有没有办法可以将Array<String>传递给此功能?按原样,编译器给我一个&#34;类型不匹配&#34;错误。

private val SOME_WORDS = arrayOf("I", "want", "to", "use", "these")

doStuff(SOME_WORDS) // throws a type-mismatch error

我希望尽可能避免SOME_WORDS成为arrayOf<String?>(...)

3 个答案:

答案 0 :(得分:4)

使用out-projected Array<out String?>

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

Arrays in Kotlin are invariant,表示Array<A>Array<B>不是任何不同AB的子类型,包括StringString?,并且不能将它们作为参数分配和传递来代替彼此。

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

type variance diagram

图片来自:A Whirlwind Tour of the Kotlin Type Hierarchy

因此,该函数也将接受Arrray<String>。但是你将无法将可空值放入数组中(这就是投影的工作原理),因此保留了类型安全性(和null安全性)。

答案 1 :(得分:4)

这里的问题是差异String是其可以为空的朋友String?的子类型,但在Kotlin中,这并不意味着Array<String>Array<String?>的子类型,因为数组不变 。 (在Java中不是这种情况,默认情况下数组是协变的)

如果你有一个像你这样的函数,它需要Array<String?>类型的参数,你只能传递Array<String?>,因此Array<String>是不可能的!如果要启用方法来处理这些数组,请执行以下操作:

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

这样就可以传递数组words 协变Array<String?>的子类型。

请注意,只有像get()这样的函数才能访问此类“out -jected”数组。参数words被称为String?制作人

如果您想了解更多相关信息,请查看官方docs:)

答案 2 :(得分:1)

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

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

Generic Inheritance

使用时,Kotlin中的out type projection与Java中的upper bounded wildcard ? extends T类似。并且String是Kotlin中String?的子集,因此{K}在{1}}扩展Array<String>。如您所见,继承图的左侧是upper bounded wildcard继承。

Upper bounded wildcard