Reputation: 43
I'm trying to combine my two functions into one using generics.
fun <T> List<T>.toElementOrSize1(keySelector: (T) -> String): String {
val key = keySelector(first())
return if (all { keySelector(it) == key }) key else "size = $size"
}
fun <T> List<T>.toElementOrSize2(keySelector: (T) -> String?): String? {
val key = keySelector(first())
return if (all { keySelector(it) == key }) key else "size = $size"
}
I could write this:
fun <T, K : String?> List<T>.toElementOrSize(keySelector: (T) -> K): K {
val key = keySelector(first())
return if (all { keySelector(it) == key }) {
key
} else {
"size = $size" as K
}
}
This works, but I've got an unchecked cast warning.
Why was this warning issued? And how to avoid this warning?
Thanks.
Upvotes: 4
Views: 4630
Reputation: 93521
The compiler isn't sophisticated enough to see that the only possible types for K
are String
and String?
(since String
is final), so to the compiler, K could be some other subtype of String?
and so casting your literal String
could be unsafe. And since K
is a generic type, the casting is unchecked due to type erasure.
There are a number of situations like this that turn up when working with generics. It doesn't mean you've necessarily done something wrong, only that the compiler doesn't know enough to be sure you didn't. You can use @Suppress("UNCHECKED_CAST")
before the function or statement to remove the warning and acknowledge that you know that it's a safe cast. This doesn't mean you're doing something hacky or poorly designed. It's used several times in the standard library source code.
Upvotes: 8