Skip to the content.

Итераторы

С итераторами пришлось разбираться довольно долго, причем трижды переделывать их чуть более чем полностью. И основная проблема заключалась в осознании того, что итераторы, например, в С++ это все же указатели на данные, для работы с которыми перегружены некоторые операции. Но они в любом случае привязаны к своим контейнерам и для работы с итераторами в С++ требуется end(), т.е. указатель на позицию “за последним элементом”.

А для NewLang такая концепция была не очень удобна, т.к. не позволяла использовать итераторы как самостоятельные объект. Хотя это очень хотелось сделать, потому что в этом случае синтаксис программы получается более простой и выразительный.

Примеры создания итераторов с разными фильтрами отбора данных:

    iter := dict ? ("name"); # Создание итератора для значений с указанным именем
    
    iter := dict ? ("regex."); # Создание итератора для полей с префиксом regex

    # Простая чистая функция предикат AND для фильтрации по значению
    filter(value) :&&= $value, $value < 10; 
    iter := dict ? (filter); # Создание итератора для значений меньше 10

    equal(value, arg) := { $value == arg }; # Обычная функция
    iter := dict ? (equal, 100); # Создание итератора только для значений 100

Оператор перебора элементов итератора ! возвращает текущий элемент и сдвигает указатель на следующий. Точнее, на количество считанных элементов, так как прочитать элементы из итератора можно не только по одному, а и заданными порциями.

Так, если указать количество считываемых элементов !(0), то будет возвращен сам элемент. Для значений отличных от нуля будет возвращаться не элемент данных, а словарь с данными, считанными из итератора. Из-за этого операторы ! и !(0) НЕ эквивалентны, т.к. по разному обработывают конец данных.

Лучше всего это показать на примерах для словаря с пятью элементами:

    dict := (1,2,3,4,5,)  ?; # Итератор для словаря

    dict!; # -> 1
    dict!; # -> 2
    dict!; # -> 3
    dict!; # -> 4
    dict!; # -> 5
    dict!; # -> будет исключение "конец итератора"

    # Но
    dict !(0); # -> (1,)
    dict !(0); # -> (2,)
    dict !(0); # -> (3,)
    dict !(0); # -> (4,)
    dict !(0); # -> (5,)
    dict !(0); # -> (,) - вернется пустой словарь

Так же для чтения итератора можно указывать и отрицательное количество элементов. В этом случае будет возвращаться словарь всегда указанного размера, но элементы в словаре будут присутствовать только в случае чтения реальных данных из итератора:

    dict := (1,2,3,4,5,)  ?; # Итератор для словаря с пятью элементами

    dict !(3); # -> (1,2,3,)
    dict !(3); # -> (4,5,)
    dict !(3); # -> (,)

    # Но
    dict !(-3); # -> (1,2,3,)
    dict !(-3); # -> (4,5, :IteratorEnd)
    dict !(-3); # -> (:IteratorEnd, :IteratorEnd, :IteratorEnd)

Остальные операторы для работы с итераторами сложностей вызвать не должны.