ch07.md 3.8 KB

Глава 7. Итераторы

Итератор — это возобновляемый proc. Итераторы обычно используются в циклах for.

Ранее уже были показаны встроенные итераторы items и ..<. Если бы они не были встроенными, их можно было бы легко определить их самостоятельно:

iterator `..<`(a, b: int): int = # 1
  var i = a
   while i < b:
     yield i                     # 2
     inc i                       # 3
iterator items(s: seq[Point]): Point =
   for i in 0 ..< s.len:        # 4
      yield s[i]
  • 1 Итератор объявляется почти так же, как proc. Оператор ..< принимает два целых числа и возвращает целое число.
  • 2 Итератор не возвращает результат, вместо этого предоставляется yield. Цикл for, вызывающий итератор ..<, вызывает ..< снова и снова, и каждый раз поток управления возобновляется с того места, на котором остановился итератор, до тех пор, пока не завершится цикл while итератора. (Когда i >= b.)
  • 3 inc i означает увеличение целого числа i на 1. Это также можно записать как i = i + 1 или i += 1.
  • 4 Итератор items вызывает итератор ..<, а итераторы вызываются в циклах for.

7.1. yield

Оператор yield можно легко представить как разновидность оператора return: оператор return возвращает управление вызывающей стороне, потенциально возвращая значение, которое может получить вызывающая сторона:

proc find(haystack: string; needle: char): int =
   for i in 0 ..< haystack.len:
      if haystack[i] == needle: return i # 1
   return -1                             # 2
   let index = find("abcabc", 'c')       # 3
  • 1 Вернуть значение i вызывающей стороне и не продолжать выполнение find. Это означает, что цикл for тоже завершается.
  • 2 Вернуть значение -1, чтобы указать, что иголка не найдена в стоге сена.
  • 3 Присвоить значение, возвращаемое функцией find, переменной index.

find возвращает индекс первого вхождения needle в haystack. Невозможно возобновить выполнение функции, чтобы найти другие возможные вхождения needle. Это может сделать итератор, например findAll, благодаря ключевому слову yield:

iterator findAll(haystack: string; needle: char): int =
   for i in 0 ..< haystack.len:
      if haystack[i] == needle: yield i       # 1
   # 2
for index in findAll("abcabc", 'c'): discard # 3
  • 1 Вернуть значение i вызывающей стороне и продолжить выполнение findAll позже.
  • 2 Обратите внимание на отсутствие оператора yield -1. Если итератор не выдаст больше значений, цикл for завершится.
  • 3 Мы перебираем все значения, возвращаемые findAll, и привязываем текущее значение к индексу.