1. 引言

在之前的文章中,我们已经了解了 Kotlin 中的 Range(范围)机制,以及如何轻松地对 Int、LongChar 类型进行范围迭代。

但如果我们想对一个 自定义类型 做同样的事情呢?答案是:当然可以!

本文将通过一个实际示例,讲解如何在 Kotlin 中为自定义类实现 Range 迭代功能。


2. 定义一个颜色类

假设我们有一个简单的类,用于表示 RGB 颜色:

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

我们的目标是实现类似这样的迭代:

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

3. 回顾 IntRange

为了实现这个功能,我们需要实现以下三个接口:

Comparable
Iterable
ClosedRange

回顾一下 Kotlin 的标准库类 IntRange

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

IntProgression 又实现了 Iterable<Int>

public open class IntProgression : Iterable<Int>

所以,我们也需要类似地实现这些接口,以便我们的类支持 .. 范围操作符。


4. 实现 ColorRange 类

我们创建一个 ColorRange 类,模仿 IntRange 的结构:

class ColorRange(override val start: CustomColor,
  override val endInclusive: CustomColor) : ClosedRange<CustomColor>, Iterable<CustomColor> {

    override fun iterator(): Iterator<CustomColor> {
        return ColorIterator(start, endInclusive)
    }
}

⚠️ 注意:由于 ClosedRange 是泛型接口,且泛型参数 T 必须继承自 Comparable<T>,所以我们还需要在 CustomColor 中实现 compareTo() 方法:

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

5. 实现 ColorIterator 类

接下来是 ColorIterator,它负责实际的迭代逻辑:

class ColorIterator(val start: CustomColor, val endInclusive: CustomColor) : Iterator<CustomColor> {

    var initValue = start

    override fun hasNext(): Boolean {
        return initValue <= endInclusive
    }

    override fun next(): CustomColor {
        val current = initValue
        initValue++
        return current
    }
}

这里我们使用了 ++ 操作符,因此必须为 CustomColor 实现 inc() 方法:

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

6. 使用自定义 Range

为了让 .. 操作符生效,我们需要在 CustomColor 中实现 rangeTo() 方法:

operator fun rangeTo(that: CustomColor) = ColorRange(this, that)

最终,完整的 CustomColor 类如下:

class CustomColor(val rgb: Int): Comparable<CustomColor> {

    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)
    }
}

✅ 测试示例 1:迭代并验证数量

@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
    }
}

✅ 测试示例 2:验证范围包含性

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

7. 总结

Kotlin 原生支持对 Int、LongChar 类型使用范围操作符。通过实现 ComparableIterableClosedRange 接口,我们也可以为自定义类添加类似功能。

通过本文的实践,你已经掌握了如何为自定义对象实现范围迭代功能。这在处理连续区间逻辑时非常实用,例如颜色渐变、日期区间、数值范围等场景。

如需查看完整代码,请访问:GitHub 仓库


原始标题:Creating a Kotlin Range Iterator on a Custom Object