Не удалось определить тип Котлина
Этот код Котлин:
fun badKotlin(text: String?): Boolean {
if (text == null) {
return true
}
var temp = text
if (false) {
temp = Arrays.deepToString(arrayOf(text))
}
return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}
не компилируется с сообщением: only safe (?.) or non null asserted (!!.) calls are allowed on a nullable receiver of type String?
Но если я добавлю else
:
fun badKotlin(text: String?): Boolean {
if (text == null) {
return true
}
var temp = text
if (false) {
temp = Arrays.deepToString(arrayOf(text))
} else {
temp = Arrays.deepToString(arrayOf(text))
}
return temp.isBlank()
}
все скомпилировано. Итак, почему вывод типа не удался?
Если я изменю тип температуры на var temp: String = text
это успешно составлено! Итак, более того, если мы изменим назначение temp следующим образом: temp = String.format("%s", text)
это тоже скомпилировано.
ОБНОВИТЬ:
Успешно скопировано:
fun badKotlin(text: String?): Boolean {
if (text == null) {
return true
}
var temp = text
if (false) {
temp = String.format("%s", text)
}
return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}
И это:
fun badKotlin(text: String?): Boolean {
if (text == null) {
return true
}
var temp: String = text
if (false) {
temp = Arrays.deepToString(arrayOf(text))
}
return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}
2 ответа
Вы можете подумать, что после
if (text == null) {
return true
}
тип text
уточняется до String
вместо String?
,
Но похоже, что это не так; вместо этого компилятор вставляет умный бросок, когда видит text
используется где String
необходимо. в
var temp = text
В строке нет причин вставлять приведение, поэтому компилятор этого не делает, а тип temp
является String?
,
Если ты пишешь
var temp: String = text
приведение необходимо, и поэтому компилятор вставляет его.
Если ты пишешь
if (...) {
temp = Arrays.deepToString(arrayOf(text))
} else {
temp = Arrays.deepToString(arrayOf(text))
}
компилятор видит, что что бы ни случилось, temp
было присвоено значение типа платформы String!
который снова может быть умным приведением к String
, Без else
филиал, этого не происходит.
РЕДАКТИРОВАТЬ:
Любопытно, если вы просто удалите if
и уходи
fun badKotlin(text: String?): Boolean {
if (text == null) {
return true
}
var temp = text
return temp.isBlank()
}
он компилируется, и если бы мое объяснение было полным, я бы этого не ожидал. Таким образом, компилятор поддерживает информацию, необходимую для интеллектуального приведения, но, похоже, его не применяют, потому что
В частности, смарт-броски применяются в соответствии со следующими правилами:...
var
локальные переменные - если переменная не изменена между проверкой и использованием, не записывается в лямбду, которая ее изменяет, и не является локальным делегированным свойством;
в if-else
В этом случае назначения в двух филиалах вместе служат еще одной проверкой; в if
-только одна ветка не
Назначая text
в temp
тип темп станет String?
, тоже. Как это:
var temp: String? = text
Так как ваш if (false)
никогда не будет выполнен, это не имеет никакого влияния на код. else
добавляет блок, который всегда выполняется (так как это в основном означает if (true)
) и назначает String
в temp
это не обнуляемо. Поскольку во втором примере temp не обнуляется, вам больше не нужно использовать операторы безопасного вызова...