ProgrammationDéveloppeur Backend / Développeur Kotlin Middle

Qu'est-ce que le surchargement d'opérateurs en Kotlin, comment l'utiliser correctement, quels écueils se présentent lors de la surcharge d'opérateurs ? Donnez un exemple détaillé et expliquez les meilleures pratiques.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Kotlin, le surchargement d'opérateurs (operator overloading) est pris en charge par le mot-clé operator. Cela permet de définir sa propre logique pour le fonctionnement des opérateurs standards (+, -, *, [], ==, etc.) pour des types utilisateur :

  • Pour cela, il faut déclarer une méthode avec le nom requis et la marquer avec le modificateur operator.
  • La liste des opérateurs pouvant être surchargés est fixée par le langage.

Exemple :

data class Vec2(val x: Int, val y: Int) { operator fun plus(other: Vec2) = Vec2(x + other.x, y + other.y) } val a = Vec2(1,2) val b = Vec2(2,3) val c = a + b // appellera operator fun plus

Nuances et meilleures pratiques :

  • Maintenez un comportement attendu (par exemple, == et equals doivent être cohérents).
  • N'abusez pas de la syntaxe opérateur si elle n'est pas évidente pour le type.
  • Il est recommandé de surcharger uniquement les opérateurs qui sont réellement logiques pour votre type.

Question piège

Quelle est la différence entre la surcharge de l'opérateur == et la redéfinition de la méthode equals() ?

Réponse : L'opérateur == en Kotlin appelle toujours la méthode equals() (avec une vérification préalable pour null). Si vous définissez operator fun equals(other: Any?): Boolean, l'opérateur == utilisera toujours cette méthode. Il n'est pas possible de faire en sorte que == et equals() fonctionnent de manière différente.

data class Point(val x: Int, val y: Int) { override operator fun equals(other: Any?): Boolean { ... } } val a = Point(1,2) val b = Point(1,2) println(a == b) // appellera a.equals(b)

Histoire

Surcharge de l'opérateur compareTo sans sémantique explicite :

Dans la classe Point, operator fun compareTo a été définie pour permettre son utilisation dans les tris. Cependant, "plus grand" et "plus petit" n'avaient pas de sens explicite, différents membres de l'équipe ont écrit une logique différente. Résultat — des bugs confus lors du tri des collections.


Histoire

Oubli de la symétrie des opérateurs pour des types mutuels :

Le développeur a implémenté operator fun plus(a: Matrix, b: Vector): Matrix, mais n'a pas assuré le fonctionnement pour Vector + Matrix, car il n'a pas implémenté la fonction symétrique. Ainsi, l'expression vector + matrix ne compilait pas, seul matrix + vector fonctionnait. Cela a provoqué des bugs dans de nombreuses parties du code.


Histoire

Surcharge erronée de l'opérateur get :

Le développeur a créé une classe personnalisée, surchargeant operator fun get(index: Int): Foo. Il n'a pas ajouté de vérifications de dépassement des limites — et une tentative d'accès à un élément inexistant renvoyait un objet avec des champs non valides, au lieu de lancer une exception — ce qui a conduit à des erreurs "invisibles" dans la logique métier.