Fonctions génériques et contraintes de types avec where
Écrivez des fonctions génériques avec une ou plusieurs contraintes de types.
Fonctions génériques et contraintes de types avec where est une leçon Kotlin Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Kotlin Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Kotlin Academy comprend 4 leçons au total.
Notions de base des fonctions génériques
Les fonctions génériques utilisent des paramètres de type entre chevrons avant le nom de la fonction. Le paramètre de type peut être utilisé dans les types des paramètres et dans le type de retour.
fun <T> identity(value: T): T = value
fun <T> listOf2(a: T, b: T): List<T> = listOf(a, b)
fun main() {
println(identity(42)) // 42
println(identity("hello")) // hello
println(listOf2(1, 2)) // [1, 2]
}Bornes supérieures avec la contrainte :
Contraignez un paramètre de type à l’aide d’une borne supérieure avec :. Le type doit être un sous-type de la borne.
fun <T : Comparable<T>> max(a: T, b: T): T = if (a >= b) a else b
fun main() {
println(max(3, 7)) // 7
println(max("apple", "banana")) // banana
// max(listOf(1), listOf(2)) // error: List is not Comparable
}Borne supérieure autorisant la valeur nulle
La borne supérieure par défaut est Any? (qui peut être nulle). Utilisez T : Any pour exclure la valeur nulle.
fun <T : Any> notNull(value: T?): T {
return value ?: throw IllegalArgumentException("Value is null")
}
fun main() {
println(notNull("hello")) // hello
try { notNull(null) } catch (e: Exception) { println(e.message) }
}Contraintes multiples avec where
Utilisez la clause where pour appliquer plusieurs contraintes à un même paramètre de type.
fun <T> process(item: T): String
where T : Comparable<T>, T : CharSequence {
return "Length=${item.length}, sorted=${item > "a"}"
}
fun main() {
println(process("kotlin")) // Length=6, sorted=true
// process(42) // error: Int doesn't implement CharSequence
}where sur une classe
La clause where fonctionne également avec les paramètres de type au niveau d’une classe.
class SortedContainer<T>(private val items: MutableList<T> = mutableListOf())
where T : Comparable<T>, T : Any {
fun add(item: T) { items.add(item); items.sort() }
fun top(): T? = items.lastOrNull()
}
fun main() {
val c = SortedContainer<Int>()
c.add(5); c.add(2); c.add(8)
println(c.top()) // 8
}Fonctions d’extension génériques
Les fonctions d’extension peuvent également avoir des paramètres de type, ce qui les rend disponibles pour des types génériques précis.
fun <T : Comparable<T>> List<T>.second(): T? {
return if (size >= 2) this[1] else null
}
fun main() {
println(listOf(10, 20, 30).second()) // 20
println(listOf("a").second()) // null
}Paramètre de type en position de retour
Les fonctions génériques peuvent déduire le type à partir du contexte, ce qui évite de spécifier explicitement les arguments de type au niveau de l’appel.
fun <T> MutableList<T>.popOrDefault(default: T): T {
return if (isEmpty()) default else removeAt(lastIndex)
}
fun main() {
val list = mutableListOf(1, 2, 3)
println(list.popOrDefault(0)) // 3
println(list.popOrDefault(0)) // 2
println(mutableListOf<Int>().popOrDefault(-1)) // -1
}Utilitaires génériques réutilisables
Les fonctions génériques rendent les fonctions utilitaires réutilisables avec différents types, sans duplication.
fun <T> Iterable<T>.firstOrElse(default: T): T = firstOrNull() ?: default
fun <T, R : Comparable<R>> Iterable<T>.maxByOrElse(selector: (T) -> R, default: T): T =
maxByOrNull(selector) ?: default
fun main() {
println(listOf<String>().firstOrElse("fallback")) // fallback
println(listOf("a","bbb","cc").maxByOrElse({ it.length }, "")) // bbb
}Projection étoilée ou caractère générique borné
Comparez l’utilisation d’un paramètre de type borné (utile lorsque vous devez produire ou consommer T) avec la projection étoilée (lorsque le type est inconnu).
fun <T : Number> sumList(list: List<T>): Double =
list.sumOf { it.toDouble() }
// Star projection: read-only, type unknown
fun printAll(list: List<*>) = list.forEach { println(it) }
fun main() {
println(sumList(listOf(1, 2, 3))) // 6.0
printAll(listOf("a", 1, true)) // a, 1, true
}Échange générique d’une paire
Une fonction générique simple, mais illustrative, qui inverse les composants d’une paire.
fun <A, B> Pair<A, B>.swap(): Pair<B, A> = Pair(second, first)
fun main() {
val pair = Pair("hello", 42)
val swapped = pair.swap()
println(swapped) // (42, hello)
}Pratique : déballage générique d’un résultat
Utilisez des génériques bornés pour écrire un utilitaire qui applique une transformation typée à un Result<T>.
fun <T : Any, R : Any> Result<T>.mapNotNull(transform: (T) -> R?): Result<R> {
return fold(
onSuccess = { v ->
val r = transform(v)
if (r != null) Result.success(r) else Result.failure(NoSuchElementException())
},
onFailure = { Result.failure(it) }
)
}
fun main() {
val r = Result.success("123")
val n = r.mapNotNull { it.toIntOrNull() }
println(n) // Success(123)
}Vérification rapide
Comment appliquer plusieurs contraintes à un seul paramètre de type ?
Récapitulatif
Les fonctions génériques utilisent des paramètres de type pour écrire du code réutilisable et sûr du point de vue des types. Utilisez : pour une seule borne ou where pour plusieurs bornes. Le compilateur Kotlin impose ces contraintes au niveau de l’appel.
Questions Fréquemment Posées
La leçon « Fonctions génériques et contraintes de types avec where » est-elle gratuite ?
Oui — le texte complet de « Fonctions génériques et contraintes de types avec where » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Kotlin Academy, passe à CoddyKit PRO. Le cours Kotlin Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Fonctions génériques et contraintes de types avec where » ?
Écrivez des fonctions génériques avec une ou plusieurs contraintes de types. Tu pratiques Kotlin Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Kotlin Academy ?
Aucune expérience préalable n'est requise. Kotlin Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Fonctions génériques et contraintes de types avec where » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Kotlin Academy ?
Oui. Chaque leçon Kotlin Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Fonctions génériques et contraintes de types avec where
- Variance au site de déclaration : in et out
- Projection étoilée et utilisation de *
- Effacement des types et paramètres de types reified