Създаване на итератор на обхват на Kotlin върху персонализиран обект

1. Въведение

В предишна статия показахме как можем да създадем диапазон в Kotlin и колко лесно е да итерираме над типове Int, Long и Char .

Но какво, ако искаме да повторим персонализиран тип ? Възможно ли е? Отговорът е да! Така че нека да влезем в кода и да видим как.

2. Цветен тип

Нека си представим, че имаме прост клас, който представлява RGB цвят:

class CustomColor(val rgb: Int): Comparable {} 

Би било хубаво да можете да итерирате в редица RGB цветове:

val a = CustomColor(0x000000) val b = CustomColor(0xCCCCCC) for (cc in a..b) { // do things }

3. Бърз поглед към IntRange

Най-просто казано, ще трябва да приложим Comparable , Iterable и ClosedRange. От предишната ни статия вече знаем, че ще трябва да внедрим Сравнимо.

За другите два интерфейса, нека се потопим в декларацията за клас IntRange за някои подсказки:

public class IntRange(start: Int, endInclusive: Int) : IntProgression(start, endInclusive, 1), ClosedRange 

И тогава, декларацията на IntProgression показва, че тя изпълнява Iterable:

public open class IntProgression : Iterable

И така, ще искаме да направим нещо подобно, за да работи тази работа.

4. Клас ColorRange

Подобно на IntRange , нека създадем клас ColorRange .

За нашите цели ще пропуснем и имитирането на IntProgression, тъй като сме съгласни да имаме стъпка по подразбиране 1. Това ще опрости малко нещата и ще ни позволи просто да приложим ClosedRange и Iterable директно :

class ColorRange(override val start: CustomColor, override val endInclusive: CustomColor) : ClosedRange, Iterable{ override fun iterator(): Iterator { return ColorIterator(start, endInclusive) } }

За нашето внедряване на итератор () ще върнем клас ColorIterator, който ще извърши тежко повдигане на действително преминаване през диапазона.

Тъй като ColorRange прилага ClosedRange интерфейс, трябва да приложим метода compareTo в клас CustomColor :

override fun compareTo(other: CustomColor): Int { return this.rgb.compareTo(other.rgb) }

5. Клас ColorIterator

ColorIterator е последното парче от пъзела:

class ColorIterator(val start: CustomColor, val endInclusive: CustomColor) : Iterator { var initValue = start override fun hasNext(): Boolean { return initValue <= endInclusive } override fun next(): CustomColor { return initValue++ } }

Имайте предвид, че initValue е от тип CustomColor. Така че, за да го мутираме с оператора ++ , ще трябва да добавим и метода inc () към CustomColor :

operator fun inc(): CustomColor { return CustomColor(rgb + 1) }

6. Използване на потребителски диапазон

Почти сме там!

Тъй като дефинираме потребителския си диапазон, класът CustomColor трябва да внедри метода rangeTo . Методът rangeTo ще ни позволи да повторим обхвата си с помощта на оператора .. , подобно на това как добавянето на inc ни позволява да използваме оператора ++ .

Нека проверим крайния продукт:

class CustomColor(val rgb: Int): Comparable { override fun compareTo(other: CustomColor): Int { return this.rgb.compareTo(other.rgb) } operator fun rangeTo(that: CustomColor) = ColorRange(this,that) operator fun inc(): CustomColor { return CustomColor(rgb + 1) } }

И това е всичко, от което се нуждаем!

И накрая, нека видим как всичко това работи заедно, като използваме набор от нашия клас CustomColor :

@Test fun assertHas10Colors(){ assertTrue { val a = CustomColor(1) val b = CustomColor(10) val range = a..b for (cc in range) { println(cc) } range.toList().size == 10 } }

В този тест дефинирахме променлива на диапазона и използвахме за итерация през обектите CustomColor , както и за трансформирането й в списък.

Нека да видим още един пример за използване на стандарта съдържа метод на обхвата:

@Test fun assertContains0xCCCCCC(){ assertTrue { val a = CustomColor(0xBBBBBB) val b = CustomColor(0xDDDDDD) val range = a..b range.contains(CustomColor(0xCCCCCC)) } }

7. Заключение

Kotlin има вградена реализация на диапазон за стойности Int, Long и Char . В тази статия научихме как да внедрим диапазон в потребителски клас.

Както винаги, кодът е достъпен в GitHub.