И новичок из Kotlin спрашивает: «почему не скомпилируется следующий код?»:
var left: Node? = null
fun show() {
if (left != null) {
queue.add(left) // ERROR HERE
}
}
Интеллектуальное приведение к «Узлу» невозможно, поскольку «left» является изменяемым свойством, которое могло быть изменено к этому времени.
Я получаю, что left
это изменяемая переменная, но я явно проверяю left != null
и left
имеет тип, Node
так почему он не может быть умно приведен к этому типу?
Как я могу это исправить элегантно? :)
n.left?.let { queue.add(it) }
я думаю?Ответы:
Между выполнением
left != null
иqueue.add(left)
другим потоком могло измениться значениеleft
наnull
.Чтобы обойти это, у вас есть несколько вариантов. Вот некоторые:
Используйте локальную переменную с умным приведением:
Используйте безопасный вызов, например, один из следующих:
Используйте оператор Элвиса с,
return
чтобы рано вернуться из функции включения:Обратите внимание, что
break
иcontinue
может использоваться аналогично для проверок внутри циклов.источник
Node
класс, определенный в исходной версии вопроса, в которомn.left
вместо простого кода был более сложный фрагмент кодаleft
. Я обновил ответ соответственно. Спасибо.val
для каждогоvar
, вложить несколько?.let
операторов, или использовать несколько?: return
операторов в зависимости от вашей функции. напримерMyAsyncTask().execute(a1 ?: return, a2 ?: return, a3 ?: return)
. Вы также можете попробовать одно из решений для «нескольких переменных let» .1) Также вы можете использовать
lateinit
Если вы уверены, что делаете инициализацию позжеonCreate()
или в другом месте.Использовать это
Вместо этого
2) И есть другой способ, который использует
!!
конец переменной, когда вы используете это такисточник
В ответе mfulton26 есть четвертый вариант.
Используя
?.
оператор, можно вызывать как методы, так и поля, не обращаясь кlet
локальным переменным и не используя их.Некоторый код для контекста:
Он работает с методами, полями и всем остальным, что я пытался заставить его работать.
Таким образом, чтобы решить проблему, вместо использования ручного приведения или использования локальных переменных, вы можете использовать
?.
для вызова методов.Для справки, это было проверено в Kotlin
1.1.4-3
, но также проверено в1.1.51
и1.1.60
. Там нет гарантии, что он работает на других версиях, это может быть новая функция.Использование
?.
оператора не может быть использовано в вашем случае, поскольку проблема заключается в передаваемой переменной. В качестве альтернативы можно использовать оператор Элвиса, и, вероятно, он требует наименьшего количества кода. Вместо использования,continue
хотя,return
также может быть использован.Можно также использовать ручное приведение, но это небезопасно:
Это означает, что если левая сторона изменилась в другом потоке, программа завершится сбоем.
источник
left
и нетqueue
. Нужно проверить это, через минуту отредактирую ответПрактическая причина, почему это не работает, не связана с потоками. Дело в том, что
node.left
эффективно переводится наnode.getLeft()
.Это свойство getter может быть определено как:
Поэтому два вызова могут не возвращать один и тот же результат.
источник
Изменить
var left: Node? = null
наlateinit var left: Node
. Задача решена.источник
Сделай это:
Который, кажется, является первым вариантом, предоставленным принятым ответом, но это то, что вы ищете.
источник
Для того чтобы свойства были Smart Cast, типом данных свойства должен быть класс, содержащий метод или поведение, к которому вы хотите обращаться, а НЕ то, что свойство относится к типу суперкласса.
например на Android
Быть:
Решение:
Использование:
GL
источник
Ваше самое элегантное решение должно быть:
Тогда вам не нужно определять новую и ненужную локальную переменную, и у вас нет новых утверждений или приведений (которые не являются СУХИМЫМИ). Другие функции области также могут работать, так что выберите ваш любимый.
источник
Попробуйте использовать оператор утверждения not-null ...
источник
Как бы я написал это:
источник