为什么Kotlin中的迭代器运算符和Iterable接口之间有分隔?

时间:2019-07-09 08:28:43

标签: kotlin

我对operator fun iterator()Iterable接口之间的分隔感到困惑。 Iterable唯一需要的功能是operator fun iterator(),它已经内置在语言中。我不知道为什么在任何情况下都可以实现operator fun iterator()而不是Iterable接口。这就引出了一个问题:为什么不用实现相应的接口就可以使某些事情变得可迭代?这样做似乎是错误的。同样,operator fun next()operator fun hasNext()是否不总是与Iterator类型相对应?

我试图检查是否为某个类型实现了operator fun iterator(),以查看它是否在后台自动实现了Iterable,但事实并非如此。我能想到的唯一另一个原因是与Java迭代器的某种互操作性。

class Foo(val n: Int) {
    operator fun iterator() = FooIterator(this) 
    // Shouldn't the language figure out that Foo is iterable?
}

class FooIterator(val foo: Foo): Iterator<Int> {
    var seen = false
    // Implementation goes here
}

fun <T> printAll(iter: Iterable<T>) {
    for (x in iter) {
        println("$x")
    }
}

fun main() {
    printAll(Foo(2)) // Type mismatch: Foo is not Iterable
}

有意义的是,任何实现iterator()next()hasNext()invoke等的类都将始终实现相应的接口。为什么用这种方式设计语言,而事实并非总是如此?

2 个答案:

答案 0 :(得分:4)

这是一条通用规则:在接口中定义具有相同名称/类型的函数不会实现该接口。为什么IterableIterator是例外? (技术术语是Kotlin中的子类型是nominal,而不是structural。)

  

我不知道为什么在任何情况下都将实现操作符fun iterator()而不是Iterable接口。

例如当iterator是扩展函数时。在the standard library

operator fun <T> Iterator<T>.iterator(): Iterator<T>
operator fun <K, V> Map<out K, V>.iterator(): Iterator<Entry<K, V>>
@JvmName("mutableIterator") operator fun <K, V> MutableMap<K, V>.iterator(): MutableIterator<MutableEntry<K, V>>

如果您很不幸无法使用旧代码,那么next() / hasNext()(还有iterator())也可以被定义为java.util.Enumeration的扩展功能。

答案 1 :(得分:2)

我的理解是operator fun iterator()operator fun next()operator fun hasNext()是在语言语法级别定义的,即它们是对语法构造中使用的对象(即{ {1}}循环。

for

另一方面,class Example { fun someFun() { for (anInt in NotIterable()) { ... } } } class NotIterable { // the 'iterator' returned is not actually an Iterator<> instance // it just an object which happen to have the right functions operator fun iterator() : NotIterator { return NotIterator() } } class NotIterator { operator fun hasNext(): Boolean { ... } operator fun next(): Int { ... } } Iterable在语言库中定义。它们建立在运算符功能之上,并添加了丰富而便捷的API,其中包括许多扩展功能。