问题
I have a function that takes in an Array<String?>
:
fun doStuff(words: Array<String?>) {
// ...
}
Is there a way I can pass in a Array<String>
to this function? As-is the compiler is giving me a "type mismatch" error.
private val SOME_WORDS = arrayOf("I", "want", "to", "use", "these")
doStuff(SOME_WORDS) // throws a type-mismatch error
Preferably I'd like to avoid making SOME_WORDS
an arrayOf<String?>(...)
if possible.
回答1:
Use an out-projected Array<out String?>
:
fun doStuff(words: Array<out String?>) { /* ... */ }
Arrays in Kotlin are invariant, meaning that Array<A>
and Array<B>
are not subtypes of each other for any different A
and B
, including String
and String?
, and they cannot be assigned and passed as arguments in place of each other.
Using an out
-projection Array<out String?>
makes the function accept not only Array<String?>
but also arrays with subtypes of String?
. Basically, since the type is final
, there's only one such subtype, and it is String
(the non-null one, without ?
).
The picture is taken from: A Whirlwind Tour of the Kotlin Type Hierarchy)
So, the function will accept Arrray<String>
as well. But you won't be able to put nullable values into the array (that's how the projection works), so the type safety (and null-safety) are preserved.
回答2:
The problem is variance here. String
is a subtype of its nullable friend String?
but in Kotlin this doen't mean Array<String>
is a subtype of Array<String?>
because arrays are invariant.
(In Java this is not the case, arrays are covariant by default)
If you have a function like yours which expects an argument of type Array<String?>
you can only pass Array<String?>
, thus Array<String>
isn't possible! If you want to enable your method to also handle these arrays do this:
fun doStuff(words: Array<out String?>) {
// ...
}
This makes the array words
covariant and subtypes of Array<String?>
are allowed to be passed.
Be aware, that only functions like get()
are accessible for such "out-projected" arrays. The Parameter words
is said to be a Producer of String?
.
If you want to learn more about it, have a look at the official docs :)
回答3:
You should use the out type projection since the generic type Array<String>
extends Any
rather than Array<String?>
in Kotlin, for example:
// v--- use out type projection here
fun doStuff(words: Array<out String?>) {
// ...
}
When use the out type projection in Kotlin is like as upper bounded wildcard ? extends T
in Java. and the String
is a subset of the String?
in Kotlin, so the Array<String>
extends Array<String?>
in Kotlin. As you can see the left side of inheritance diagram is the upper bounded wildcard inheritance.
来源:https://stackoverflow.com/questions/45866466/pass-array-of-non-nullable-strings-as-array-of-nullable-strings