Ce face operator
În Kotlin operatorii sunt de fapt apeluri de funcții cu nume fixe. a + b înseamnă a.plus(b), a[i] înseamnă a.get(i), x in a înseamnă a.contains(x), a < b înseamnă a.compareTo(b) < 0. Ca operatorul să meargă pe clasa ta, scrii funcția cu numele respectiv și o marchezi cu operator.
Nume des folosite: plus, minus, times, div, rem (aritmetici), unaryMinus, inc, dec, get/set (indexare), contains (in), rangeTo (..), compareTo, invoke (apel ca funcție), componentN (destructurare), getValue/setValue (proprietăți delegate). == folosește equals, care nu are nevoie de operator (se suprascrie cu override).
+= folosește plusAssign dacă există, altfel a = a + b (pentru var). Operatorii pot fi scriși și ca extensii, deci poți adăuga + unei clase pe care nu o poți modifica.
Exemple
Exemplul 1: Bani: plus, times și compareTo
Clasa Bani păstrează suma în bani (întregi). Datorită funcțiilor operator, sumele se adună, se înmulțesc și se compară cu operatorii obișnuiți.
data class Bani(val bani: Long) : Comparable<Bani> {
operator fun plus(alt: Bani) = Bani(bani + alt.bani)
operator fun times(n: Int) = Bani(bani * n)
override operator fun compareTo(other: Bani) = bani.compareTo(other.bani)
override fun toString() = "${bani / 100},${(bani % 100).toString().padStart(2, '0')} lei"
}
fun main() {
val paine = Bani(450)
val lapte = Bani(799)
var total = paine * 2 + lapte
println("Total: $total")
total += Bani(1001)
println("Cu ouă: $total")
println("Pâinea e mai ieftină decât laptele? ${paine < lapte}")
}
Rezultat
Total: 16,99 lei
Cu ouă: 27,00 lei
Pâinea e mai ieftină decât laptele? true
Exemplul 2: Indexare cu get/set și operatorul in
catalog["Ana"] apelează get, atribuirea apelează set, iar "Ana" in catalog apelează contains.
class Catalog {
private val note = mutableMapOf<String, Int>()
operator fun get(elev: String): Int = note[elev] ?: 0
operator fun set(elev: String, nota: Int) { note[elev] = nota }
operator fun contains(elev: String) = elev in note
}
fun main() {
val catalog = Catalog()
catalog["Ana"] = 10
catalog["Mihai"] = 7
println("Ana: ${catalog["Ana"]}")
println("Ioana: ${catalog["Ioana"]}")
println("Mihai este în catalog? ${"Mihai" in catalog}")
println("Ioana lipsește din catalog? ${"Ioana" !in catalog}")
}
Rezultat
Ana: 10
Ioana: 0
Mihai este în catalog? true
Ioana lipsește din catalog? true
Exemplul 3: invoke și operator ca extensie
Un obiect cu invoke poate fi apelat ca o funcție. unaryMinus este adăugat ca extensie pe Pair, o clasă din biblioteca standard.
class Salut(private val formula: String) {
operator fun invoke(nume: String) = "$formula, $nume!"
}
operator fun Pair<Int, Int>.unaryMinus() = Pair(-first, -second)
fun main() {
val buna = Salut("Bună dimineața")
println(buna("Elena"))
println(buna("Radu"))
val punct = 3 to -5
println(-punct)
}
Rezultat
Bună dimineața, Elena!
Bună dimineața, Radu!
(-3, 5)
Greșeli frecvente
- Uitarea cuvântului
operator: funcțiaplusexistă, dara + bdă eroarea'operator' modifier is required on 'fun plus(alt: Bani): Bani'. - Nume greșit: operatorii au nume fixe (
times, numultiply;div, nudivide). - Operatori cu sens surprinzător (de exemplu
+care șterge ceva): păstrează sensul matematic obișnuit, altfel codul înșală cititorul.
Comenzi înrudite
infix: infix permite apelarea unei funcții cu un parametru fără punct și paranteze: a to b în loc de a.to(b).Destructuring (val (a, b) = ...): Destructuring desface un obiect în mai multe variabile deodată: val (nume, nota) = pereche.in și !in: in verifică dacă o valoare aparține unui interval, unei colecții sau unui text; tot in se folosește în for.Proprietăți delegate (by lazy, observable, map): O proprietate delegată (val x by …) lasă un alt obiect să decidă ce se întâmplă la citire și scriere: lazy, observable, map.data class: data class este o clasă pentru date: primește automat toString, equals, hashCode, copy și componentN.