web-dev-qa-db-fra.com

Quand exactement le mot-clé opérateur est-il requis dans Kotlin?

Dans le 14e Kotlin Koan sur la surcharge de l'opérateur, j'ai été surpris quand après la résolution j'ai vu la réponse et j'ai vu que le modificateur operator n'était pas requis sur la méthode compareTo:

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
    override fun compareTo(other: MyDate) = when {
        year != other.year -> year - other.year
        month != other.month -> month - other.month
        else -> dayOfMonth - other.dayOfMonth
    }
}

Le opérateur surchargeant les documents lié à de l'exercice dit explicitement:

Les fonctions qui surchargent les opérateurs doivent être marquées avec le modificateur d'opérateur.

Alors qu'est-ce qui se passe ici? Pourquoi ce code se compile-t-il? Quand est exactement operator requis?

20
Tom Tresansky

Pourquoi ce code se compile-t-il?

Cela se compile car la méthode d'interface remplacée, Comparable<T>.compareTo , est un operator fun.

/**
 * Compares this object with the specified object for order. Returns zero if this object is equal
 * to the specified [other] object, a negative number if it's less than [other], or a positive number
 * if it's greater than [other].
 */
public operator fun compareTo(other: T): Int

Comme la fonction l'emporte, c'est aussi une fonction opérateur.

Quand est exactement operator requis?

operator en général est requis chaque fois que vous souhaitez pouvoir utiliser une fonction comme s'il s'agissait d'un opérateur, car les opérateurs sont simplement compilés pour appeler des fonctions (sauf sur les types primitifs, etc.)

Autrement dit, foo += bar, Par exemple, est équivalent à foo.plusAssign(bar), foo[bar] = baz Est équivalent à foo.set(bar, baz), etc.

Personnellement, je préfère spécifier operator dans la mesure du possible, même si ce n'est pas nécessaire, pour des raisons de lisibilité.

Si MyDate n'était pas un Comparable, et que vous avez omis le modificateur operator, en comparant deux dates via <, >, <= ou >= ne seront pas compilés.

Cependant, je n'ai rien trouvé dans la spécification . Cependant, dans un sens polymorphe, cela a du sens - pourquoi devriez-vous être en mesure d'écrire a < b Où le type de a et b sont des Comparable, mais pas quand ils sont un MyDate? Comme vous ne pourrez pas supprimer "l'opératrice" de cette fonction, il est logique que operator soit héritable de la méthode de la superclasse.

12
Moira

Kotlin possède de nombreuses fonctionnalités qui sont activées via des conventions particulières . Ceux-ci peuvent être identifiés à l'aide d'un mot clé operator. Les exemples sont plages, surcharges d'opérateur, opérateurs d'index, déclarations de déstructuration et plus .

Si nous voulons comparer deux objets en Java, pour le tri par exemple, nous implémentons l'interface Comparable avec sa méthode compareTo. Cela se fait également dans Kotlin, mais avec un bien meilleur support et une syntaxe abrégée. Si vous implémentez cette méthode dans une classe, vous pouvez utiliser tous les opérateurs Nice comme <, <=, >, >= Avec cette classe hors du boîte. Ces opérateurs sont traduits en appels appropriés de compareTo par le compilateur:

obj1 > obj2obj1.compareTo(obj2) > 0

La méthode d'interface compareTo dans Comparable définit déjà le mot clé operator, ce qui rend redondant l'ajout du mot clé dans votre propre implémentation.

Dans votre exemple, le mot clé operator n'est pas obligatoire car la méthode substituée le définit déjà.

5
s1m0nw1

En Java, les opérateurs sont liés à des types spécifiques Java. Par exemple, les types String et numériques dans Java peuvent utiliser l'opérateur + pour la concaténation et l'addition, respectivement). Aucun autre type Java ne peut réutiliser cet opérateur pour son propre bénéfice. Kotlin, au contraire, fournit un ensemble de conventions pour prendre en charge une surcharge d'opérateur limitée.

Commençons par une classe de données simple:

data class Point(val x: Int, val y: Int)

Nous allons améliorer cette classe de données avec quelques opérateurs.

Afin de transformer une fonction Kotlin avec un nom prédéfini en opérateur, nous devons marquer la fonction avec le modificateur d'opérateur. Par exemple, nous pouvons surcharger l'opérateur "+":

operator fun Point.plus(other: Point) = Point(x + other.x, y + other.y)

De cette façon, nous pouvons ajouter deux points avec "+":

val p1 = Point (0, 1)

val p2 = Point (1, 2)

println (p1 + p2)

Point (x = 1, y = 3)