问题
When I'm trying to create the following code:
class SmartCast {
var array: MutableList<Int>? = null
fun processArray() {
if (array != null && !array.isEmpty()) {
// process
}
}
}
this error is shown:
Smart cast to 'MutableList' is impossible, because 'array' is a mutable property that could have been changed by this time
It's clear that the array
variable can be changed to null
in case of multi-threading. But if I use @Synchronized
annotation, there is no way to mutate the variable in between array != null
and !array.isEmpty()
.
@Synchronized
fun processArray() {
I'm wonder, why the compiler doesn't allow smart cast in synchronized blocks or maybe it's possible to specify somehow that my application is designed only for single-threaded mode?
UPDATE: According to the answers, I changed the code in the following way:
fun processArray() {
array?.takeUnless { it.isEmpty() }?.also {
for (elem in it)
// process elements
}
}
回答1:
why the compiler doesn't allow smart cast in synchronized blocks
Because this
But if I use @Synchronized annotation, there is no way to mutate the variable in between array != null and !array.isEmpty().
is wrong. @Synchronized
means this method can't be called by two threads at the same time, but another thread which has access to the same instance is perfectly free to reassign array
.
You also need to mark the setter as @Synchronized
, in which case it really can't be changed at the moment. But trying to figure out exactly when smart casts are safe would lead to very complex rules, and minor changes in one method suddenly breaking smart casts in others. So the rules are conservative instead.
回答2:
Save the list to a local variable, and use that local variable. An elegant way to do that is to use the let
function, and to combine it with the null-safe operator:
array?.let {
if (!it.isEmpty()) {
// process it
}
}
This is described in the idioms section of the getting started guide, BTW.
回答3:
Kotlin 1.3 introduced a function for that:
fun <T> Collection<T>?.isNullOrEmpty(): Boolean
So,
class SmartCast {
var array: MutableList<Int>? = null
fun processArray() {
if(!array.isNullOrEmpty()){
// processs
}
}
}
will compile.
来源:https://stackoverflow.com/questions/50885684/kotlin-smart-cast-with-nullable-variable