Intereting Posts
Невозможно заменить SAM-конструктор лямбдой, когда первый аргумент – это класс с одним методом Ошибка Null Pointer в ссылке RecyclerView в фрагменте с использованием Kotlin Почему getMessage () является нерешенной ссылкой в ​​Kotlin с классом Exception? Как инициализировать контрольную переменную в Котлине Как «продолжить» или «ломать» в выражении `when` внутри цикла while, используя Kotlin Как вы скрываете параметры в шагах пользовательской сборки в Kotlin для TeamCity? Как правильно использовать URL-адрес с Kotlin Android Переменные деструктурирования Kotlin не работают с Pair, Triple или классом данных Класс Котлина не найден при построении с дженкинсами котлинское деление нулевых аргументов Динамический текст над кнопкой поиска IDEA показывает проект дважды в дереве Как реализовать экспоненциально уменьшающуюся средневзвешенную Котлин и привязка к Android Встроенная функция не может получить доступ к непубличным API: @PublishedApi vs @Suppress vs @JvmSynthetic

Нулевые проверки не вставляются для типа reified, если параметр не является нулевым

TL; DR. Если функции с типами reified учитывают значение null-параметра при генерации кода?

Прецедент

Рассмотрим следующий код Котлина; единственная разница между этими двумя методами заключается в том, является ли ограничение типа нулевым ( Any? ) или нет ( Any ).

 @Test fun testNonNullableBound() { val x: Int = nonNullableBound() } @Test fun testNullableBound() { val x: Int = nullableBound() } private inline fun <reified T : Any> nonNullableBound(): T { return unsafeMethod() } private inline fun <reified T : Any?> nullableBound(): T { return unsafeMethod() } 

где unsafeMethod подрывает систему типов путем определения в Java:

 public static <T> T unsafeMethod() { return null; } 

Это Kotlin 1.1.4.

Ожидаемое поведение

Я ожидаю, что они будут вести себя эквивалентно – тип подтверждается, поэтому фактическое значение T как известно, не является нулевым, поэтому нулевая проверка должна быть применена внутри функции до оператора return .

Наблюдаемое поведение

Эти два случая не срабатывают по-разному:

  • testNonNullableBound ведет себя как ожидалось (сбой из-за нулевой проверки значения, возвращаемого unsafeMethod() ).
  • testNullableBound не ведет себя так, как ожидалось, – он терпит неудачу с NPE при выполнении задания на x .

Таким образом, кажется, что вставка нулевых проверок основана на привязке типа, а не на фактическом типе.

Анализ

Для справки соответствующий байт-код выглядит следующим образом. Обратите внимание на нулевую проверку, добавленную в testNonNullableBound .

testNonNullableBound

 public final testNonNullableBound()V @Lorg/junit/Test;() [...] L1 LINENUMBER 28 L1 INVOKESTATIC JavaStuff.unsafeMethod ()Ljava/lang/Object; DUP LDC "unsafeMethod()" INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V [...] 

testNullableBound

 public final testNullableBound()V @Lorg/junit/Test;() [...] L1 LINENUMBER 27 L1 INVOKESTATIC JavaStuff.unsafeMethod ()Ljava/lang/Object; [...] 

Таким образом, кажется, что вставка нулевых проверок основана на привязке типа, а не на фактическом типе.

Правильно, так оно и должно работать!

Функция JVM не может иметь разные байтовые коды в зависимости от фактического общего типа, поэтому одна и та же реализация должна удовлетворять всем возможным результатам.

Вложение не влияет на этот случай, поскольку оно следует тем же правилам, что и обычные функции. Он был спроектирован таким образом, чтобы разработчик был менее удивлен.

Проблема заключается не в том, что функция включена или нет.

Из документации Котлина:

Любая ссылка в Java может быть нулевой, что делает требования Котлина о строгой нулевой безопасности нецелесообразными для объектов, поступающих с Java. Типы объявлений Java обрабатываются специально в Kotlin и называются типами платформ. Null-чеки смягчены для таких типов, так что гарантии безопасности для них такие же, как в Java

Используя @Nullable аннотацию, в java-стороне, вы можете принудить kotlin проверить, может ли тип быть нулевым или нет (используя @NotNull )

 @Nullable public static <T> T unsafeMethod() { return null; }