6
votes

Kotlin 1.3.11 a cassé la sécurité nulle?

fun handle() : String {
    null?.let { return "Ololo"}
}

val result = handle()
result.trim() // kotlin.TypeCastException: null cannot be cast to non-null type kotlin.CharSequence
Any ideas why null-safe Kotlin function return null?

8 commentaires

Je ne pense pas que let fonctionnera si sa référence est nulle.


null? .let {}. Quoi?


@ DawidJamroży dans le cas d'utilisation réel, j'ai une variable à la place null codée en dur


Cela ressemble à un bogue du système de type Kotlin. Il semble qu'il ne devrait pas être compilé à moins que le type de retour ne soit String?


@Brucelet il ne devrait pas du tout compiler. let () n'est censé s'exécuter que si sa référence n'est pas nulle, ce qui signifie qu'il y a techniquement une instruction return manquante. Il semble que le compilateur ajoute actuellement un return null .


Oui, vous avez raison. Je le lisais comme s'il était return null? .Let {...}


@NickolaySavchenko J'ai édité votre question, car elle n'est pas liée à Android.


Il n'y a pas de return et pourtant il se compile. Méchant bug


3 Réponses :


4
votes

Il semble que le compilateur Kotlin ajoute un retour null au cas où let ne s'exécuterait pas. C'est probablement un bogue, car il ne devrait pas se compiler, et ce n'est pas le cas dans les versions précédentes de Kotlin.

Si nous compilons simplement votre exemple, nous obtenons ceci:

fun handle(): String {
    someNullableVariable?.let { return "Ololo" }
    return "someNullableVariable was null"
}

Je pense que ce n'est qu'une optimisation du compilateur, puisque null? .let () ne s'exécutera jamais.

L'utilisation d'une variable réelle donne:

fun handle(): String? {
    someNullableVariable?.let { return "Ololo" }
}


1 commentaires

Merci pour votre explication. Cela ressemble à un bogue du compilateur Kotlin, car sur des versions plus antérieures, le code n'était pas compilable. Et c'est un comportement attendu du langage null-safe à mon avis.



3
votes

Cela doit être un bogue, car:

  • une instruction return (ou mieux: expression) est manquante, car le lambda passé à let ne sera pas appelé
  • une fonction avec String comme type de retour ne doit jamais renvoyer null .

Fait intéressant, dans Kotlin 1.2.x cela ne compile même pas:

fun handle() : String {
    null?.let { return "Ololo"}
} 

Erreur: (6, 0) Une expression 'return' requise dans une fonction avec un corps de bloc ('{...}')

Dans Kotlin 1.3.11 c'est le cas.

Dans tous les cas:

let ne sera pas invoqué, car le coffre-fort L'opérateur -call ? est évalué à null (dans ce cas).


6 commentaires

Il se compile pour moi avec Kotlin 1.3.11 sur Android Studio 3.4.


@TheWanderer True Je l'ai collé dans le terrain de jeu en ligne de kotlin et j'ai accidentellement utilisé la version 1.2.71. THX


C'est vraiment bizarre / intéressant; Avec return uniquement dans le bloc let , il ne retournera rien si le bloc n'est pas exécuté. Comme il ne s'exécute jamais, cela ne renvoie jamais rien. fun handle (): String {} ne devrait pas être compilé en premier lieu, car il y a une chance qu'il ne revienne pas. Autrement dit, à moins que Kotlin ne renvoie maintenant les valeurs par défaut si aucune n'est spécifiée, mais ce serait vraiment étrange. On dirait un bug


@Zoe vérifie ma réponse. Il ajoute un retour nul


@TheWanderer oui, mais ça ne devrait pas. Il n'y a aucune partie de ce code qui aurait un retour de secours.


@Zoe c'est vraiment bizarre: D



9
votes

C'est un bug causé par l'introduction de contrats pour les fonctions standard laissez , run , apply , aussi dans Kotlin 1.3.

Le correctif est destiné à la version 1.3.20. Voir KT-28061 pour plus de détails.


1 commentaires

Merci pour la réponse, gentil.