Intereting Posts
Потеря данных при повороте экрана Диалог поиска в Mono Android Установка Android sdk. Ошибка: был найден недопустимый контент, начиная с элемента 'd: skin'. На данный момент не ожидается никакого дочернего элемента Android получает вид вида Eclipse JUNO не запускается Ошибка: org.apache.http.conn.HttpHostConnectException: подключение к http://10.0.2.2:8080 отказано Диалог поиска не вызывается onSearchRequested () Как установить значок каждой вкладки в файле фрагментарный фрагмент в анимацию gif? Примените много цветных фильтров к одному и тому же извлекаемому ClickListener в PagerAdapter срабатывает в неправильном положении Добавление прорисовки на вид программно Выполнение горизонтальной / вертикальной прокрутки пальцев в сотовом андроидном веб-виде / webkit? Android – выбор фокус на растровое изображение Тестовый пакет для разных вкусов в Android Studio Контакты Android Отображаемое имя и номер телефона (ы) в запросе одной базы данных?

Smartcast невозможно, потому что у владельца есть открытый или пользовательский getter

Я изучаю Котлин. Мой код выглядит следующим образом:

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) decoupler.attachNotifier(this) if(activity is ScreenRouter) { decoupler.attachRouter(activity) } } 

attachRouter() метод:

  fun attachRouter(router: ScreenRouter?) { this.router = router } 

Как написано в документации , kotlin автоматически присваивает тип после проверки с оператором. Поэтому я ожидал, что это сработает. Но вместо этого это беспокоит меня ошибкой компиляции:

Smartcast для ScreenRouter невозможно, потому что activity – это свойство, которое имеет открытый или пользовательский getter.

Я думал, может быть, ошибка в том, что активность может быть нулевой, поэтому я попытался:

 if(activity!=null && activity is ScreenRouter) { decoupler.attachRouter(activity) } 

Но это не сработало, и компиляция завершилась с той же ошибкой.

Однако, следующий код работает нормально:

 if(activity is ScreenRouter) { decoupler.attachRouter(activity as ScreenRouter) } 

Все в порядке, но выше ошибки, похоже, ничего не объясняет, почему Smartcast не удается. Я не эксперт по Котлину, я просто начинаю изучать Котлина. Я не нашел никакой документации нигде. Подобные описания ошибок заставляют Котлина учиться. Может ли кто-нибудь объяснить в простых терминах?

Solutions Collecting From Web of "Smartcast невозможно, потому что у владельца есть открытый или пользовательский getter"

Ключевым моментом здесь является то, что свойство open или свойство с пользовательским получателем не гарантируют возврата того же значения при последовательных вызовах к нему.

Поэтому компилятор не может быть уверен, что после проверки значения, полученного от свойства, можно с уверенностью предположить, что он снова вернет тот же объект или даже объект того же типа, если он снова вызван.

Пример (довольно упрощенный и синтетический):

 open class Base { open val value: List<Int> = ArrayList() } val b : Base = foo() fun printArrayList(list: ArrayList<Int>) { /* ... */ } if (b.value is ArrayList) { // first call printArrayList(b.value) // second call, smart cast is impossible } 

Этот код не будет компилироваться, потому что printArrayList() ожидает, что ArrayList и b.value будут open – это то, что вы получаете в своем коде. Теперь давайте создадим производный класс, который продемонстрирует, что может пойти не так:

 class Derived : Base() { private var counter = 0 override val value: List<Int> get() { ++counter return if (counter % 2 == 0) ArrayList() else LinkedList() } } val b = Derived() println(b.value.javaClass) // class java.util.LinkedList println(b.value.javaClass) // class java.util.ArrayList 

Здесь совершенно очевидно, что если свойство open , оно может быть переопределено таким образом, что последовательные вызовы к нему возвращают разные значения. В примере с printArrayList() есть два таких вызова. Вот почему умный актер не будет в безопасности. То же самое верно для свойств с пользовательскими геттерами.

Ваш пример, который выполнял as -cast внутри блока if работал, потому что приведение было неудачным и ClassCastException если свойство возвращало другое значение несовместимого типа во втором вызове, и это сохранит безопасность типа.

И наоборот, если свойство val не open и имеет по умолчанию getter, который просто возвращает значение поля поддержки (что в final является final ), компилятор может безопасно выполнить интеллектуальный приведение: если вы получите значение Свойство несколько раз, несомненно, будет одним и тем же.


Альтернативой является получение значения один раз, сохранение его в локальной переменной и использование его несколько раз вместо повторного использования свойства:

 val list = b.value if (list is ArrayList) { printArrayList(list) // smart cast to ArrayList } 

Теперь, независимо от того, открыто ли свойство, есть только один вызов его получателю, и тогда код работает со значением, возвращаемым вызовом. Так как он не может измениться, здесь возможно умение.