Kotlin : run, let, apply, also, with — quand utiliser quoi ? Analyse complète avec exemples
Bonjour, ami ! Si tu étudies Kotlin et souhaites écrire un code propre et concis, tu rencontreras tôt ou tard cinq fonctions magiques : run, let, apply, also et with. Ce sont des fonctions de portée (scope functions) — elles permettent d'exécuter du code dans le contexte d'un objet et simplifient grandement la vie.
Mais voilà le problème : beaucoup de débutants (et pas seulement) se mélangent les pinceaux sur quand les utiliser. Cette question est l'une des plus populaires sur Stack Overflow, et aujourd'hui nous allons une fois pour toutes comprendre comment ne pas se tromper. Nous ne nous contenterons pas d'énumérer les règles — nous montrerons des exemples réels issus de la pratique que tu pourras utiliser immédiatement dans tes projets.
Que sont les fonctions de portée et à quoi servent-elles ?
Les fonctions de portée sont des fonctions qui créent une portée temporaire pour un objet. À l'intérieur de cette portée, tu peux accéder à l'objet via it ou this. La principale différence entre elles réside dans la manière dont elles retournent le résultat et comment elles se réfèrent au contexte.
Voici un aide-mémoire rapide que nous allons enrichir d'exemples :
let— contexte :it, retourne : le résultat de la lambda. Utilisé pour les vérifications non nulles et les chaînes d'appels.run— contexte :this, retourne : le résultat de la lambda. Fonction universelle, souvent pour l'initialisation et les calculs.apply— contexte :this, retourne : l'objet lui-même. Idéal pour configurer les propriétés d'un objet.also— contexte :it, retourne : l'objet lui-même. Bon pour les actions supplémentaires (journalisation, vérifications).with— n'est pas une fonction d'extension, contexte :this, retourne : le résultat de la lambda. Pratique pour regrouper les appels d'un même objet sans en créer un nouveau.
Rappelle-toi la règle principale : le choix de la fonction dépend de ce dont tu as besoin — retourner l'objet ou le résultat, et de la manière dont tu souhaites accéder au contexte (via it ou this).
1. let — le roi des chaînes sécurisées
let est ton meilleur ami quand tu dois travailler avec des objets nullable. Il exécute le code uniquement si l'objet n'est pas nul. Le contexte est passé en tant que it.
Exemple : transformation sécurisée
val name: String? = "André"// Sans let :if (name != null) { println("Longueur du nom : ${name.length}")}
// Avec let (beaucoup plus élégant) :name?.let { println("Longueur du nom : ${it.length}")}let convient également parfaitement pour les chaînes d'opérations. Par exemple, lorsque tu dois transformer un objet en un autre :
val numbers = listOf(1, 2, null, 4, null, 6)val nonNullSquared = numbers .mapNotNull { it } .let { list -> list.map { it * it } }println(nonNullSquared) // [1, 4, 16, 36]Quand utiliser let :
- Vérification de null (le cas le plus fréquent).
- Transformation d'une valeur en une autre.
- Exécution d'une chaîne d'opérations avec le résultat.
2. apply — un constructeur sans mots superflus
apply retourne l'objet lui-même, et à l'intérieur de la lambda, le contexte est this. C'est l'outil idéal pour configurer un objet avant son utilisation. Oublie les longs blocs de set !
Exemple : configuration d'une View (Android) ou d'une data class
data class User(var name: String = "", var age: Int = 0)
val user = User().apply { name = "Marie" age = 25}println(user) // User(name=Marie, age=25)
// Encore mieux — configuration d'un TextView :val textView = TextView(context).apply { text = "Bonjour, Kotlin !" textSize = 18f setTextCo