Привет!
Сегодня мы поговорим зачем нужно ключевое слово operator в Kotlin.
Если коротко, то оно служит, чтобы расширить стандартные операции языка (такие как +, - , * и другие) на ваши собственные типы данных.
По умолчанию Котлин умеет складывать, умножать, вычитать, делить, инкрементировать (да много чего еще) со числовыми типами данных, умеет соединять строки, добавлять значения в массивы и тд. Это известно и понятно, но мы бы хотели научить Котлин работать так же с наши классами. Вот тут нам и поможет ключевое слово operator.
Давайте рассмотрим на примере как работать с этой фичей. Будет очень красиво, обещаю :)
👉 Допустим есть класс Point, который представляет собой точку на плоскости. Он хранит в себе x и y значения. Вот он кстати:
class Point(val x: Int, val y: Int)
Очень хочется чтобы могли взять две точки и сложить или вычесть, чтобы получить новую координату, но сделать это красиво, вот так, например:
val x1 = Point(1,1)
val x2 = Point(2,2)
val result = x1 + x2
Котлин не умеет работать с нашим классом Point по умолчанию, и знак «плюс» тут не сработает, но давайте его научим этому. Напишем функцию plus в классе Point:
class Point(val x: Int, val y: Int){
operator fun plus (p : Point) : Point {
return Point(this.x + p.x, this.y + p.y)
}
}
Теперь Котлин перестанет подчеркивать знак + красным, и легко выполнит
val result = x1 + x2
Так, стоп! что именно мы написали? Мы написали функцию перегрузки стандартного оператора +, поэтому функция называется plus. Есть целая таблица операций, которым сопоставлено название соответствующих операций. Вот небольшая её часть:
👉 Пользуясь таблицей мы можем теперь перегрузить оператор «минус», например. А ключевое слово operator просто сообщает Котлину, что мы хотим перегрузить оператор +, а не просто написать какую-то свою функцию с таким именем.
Вот и пример с «минусом» подоспел:
class Point(val x: Int, val y: Int) {
operator fun plus(p: Point): Point {
return Point(this.x + p.x, this.y + p.y)
}
operator fun minus(p: Point): Point {
return Point(this.x - p.x, this.y - p.y)
}
}
fun main() {
val x1 = Point(1, 1)
val x2 = Point(2, 2)
val result = x1 + x2
val result2 = result - Point(3, 3)
println(result2.toString())
}
👉 Вот, думаю теперь всё понятно, и вопросов тут быть не должно. Мы могли бы еще x++ подобным образом сделать, но давайте лучше сделаем нечто похожее с коллекциями. Предположим у нас есть класс Shelf, это книжная полка, которая содержит Books в списке List и мы бы хотели добавлять книги туда, брать от туда, а так же смотреть что там есть. Так что, давайте сразу перегрузим 3 функции в классе Shelf:
class Book(val name : String)
class Shelf(val books : MutableList<Book> = mutableListOf()) {
operator fun get(id: Int) = books[id]
operator fun set(id: Int, product: Book) {
books.add(id, product)
}
operator fun contains(book: Book) = book in books
}
Работать с книгами на полке мы можем теперь так:
fun main() {
val shelf = Shelf()
val book = Book("Война и мир")
shelf[0] = book //set
println(shelf[0].name) //get
println(shelf.contains(book)) //contains
}
Что приятнее и короче чем писать
shelf.books[0] = book
println(shelf.books[0].name)
println(shelf.books.contains(book))
👉 Хорошо, с этим разобрались. Полную таблицу поддерживаемых операций я приведу ниже, глядя на которую, вы сможете сами выбрать куда ещё добавить немного сахарку в своем коде =) Поэкспериментируйте с другими операциями самостоятельно.
На этом пока всё. Ждите следующих выпусков. Поставьте лайк если понравилось, а так же не забывайте подписываться на канал. Увидимся!