Почему в Kotlin существует разделение между оператором итератора и интерфейсом Iterable? - PullRequest
1 голос
/ 09 июля 2019

Я очень озадачен разделением между 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 ]

4 голосов
/ 09 июля 2019

Это общее правило: определение функций с тем же именем / типом, что и в интерфейсе, не реализует интерфейс. Почему Iterable и Iterator должны быть исключениями? (Технический термин заключается в том, что подтип в Kotlin номинальный , а не структурный .)

Я не могу понять, почему в любом случае вы бы реализовали операторный итератор (), но не интерфейс Iterable.

например. когда iterator является функцией расширения. В стандартная библиотека

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 на случай, если вам не повезло работать со старым кодом, использующим его.

2 голосов
/ 09 июля 2019

Насколько я понимаю, operator fun iterator(), operator fun next() и operator fun hasNext() определены на уровне синтаксиса языка, то есть они являются низкоуровневыми требованиями к объектам, которые будут использоваться в синтаксических конструкциях (а именно 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 и Iterator определены в языковой библиотеке.Они построены на основе функций оператора и добавляют богатый и удобный API, включая довольно много функций расширения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...