Spec-Zone.ru › Go

Пакет iter

  • import "iter"
  • Обзор
  • Индекс

Обзор

Пакет iter предоставляет основные определения и операции, связанные с итераторами по последовательностям.

Итераторы

Итератор — это функция, которая передает последовательные элементы последовательности в функцию обратного вызова, традиционно называемую yield. Функция останавливается либо когда последовательность заканчивается, либо когда yield возвращает false, указывая на то, что итерацию следует остановить преждевременно. Этот пакет определяет Seq и Seq2 (произносится как сик — первая слога последовательности) как сокращения для итераторов, которые передают 1 или 2 значения на элемент последовательности в yield:

type (
	Seq[V any]     func(yield func(V) bool)
	Seq2[K, V any] func(yield func(K, V) bool)
)

Seq2 представляет последовательность пар значений, как правило, пар ключ-значение или индекс-значение.

Yield возвращает true, если итератор должен продолжить с следующим элементом в последовательности, false, если он должен остановиться.

Функции итератора чаще всего вызываются циклом range, как в:

func PrintAll[V any](seq iter.Seq[V]) {
	for v := range seq {
		fmt.Println(v)
	}
}

Соглашения об именах

Функции и методы итератора названы в соответствии с последовательностью, по которой происходит обход:

// All returns an iterator over all elements in s.
func (s *Set[V]) All() iter.Seq[V]

Метод итератора для типа коллекции обычно называется All, потому что он итерирует последовательность всех значений в коллекции.

Для типа, содержащего несколько возможных последовательностей, имя итератора может указывать, какая последовательность предоставляется:

// Cities returns an iterator over the major cities in the country.
func (c *Country) Cities() iter.Seq[*City]

// Languages returns an iterator over the official spoken languages of the country.
func (c *Country) Languages() iter.Seq[string]

Если итератору требуется дополнительная конфигурация, функция конструктора может принимать дополнительные аргументы конфигурации:

// Scan returns an iterator over key-value pairs with min ≤ key ≤ max.
func (m *Map[K, V]) Scan(min, max K) iter.Seq2[K, V]

// Split returns an iterator over the (possibly-empty) substrings of s
// separated by sep.
func Split(s, sep string) iter.Seq[string]

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

// All returns an iterator over the list from head to tail.
func (l *List[V]) All() iter.Seq[V]

// Backward returns an iterator over the list from tail to head.
func (l *List[V]) Backward() iter.Seq[V]

// Preorder returns an iterator over all nodes of the syntax tree
// beneath (and including) the specified root, in depth-first preorder,
// visiting a parent node before its children.
func Preorder(root Node) iter.Seq[Node]

Итераторы одноразового использования

Большинство итераторов предоставляют возможность пройти по всей последовательности: при вызове итератор выполняет все необходимые настройки для начала последовательности, затем вызывает yield для последовательных элементов последовательности и затем очищает перед возвратом. Вызов итератора снова проходит по последовательности еще раз.

Некоторые итераторы нарушают это соглашение, предоставляя возможность пройти по последовательности только один раз. Эти «итераторы одноразового использования» обычно сообщают значения из потока данных, который нельзя перемотать, чтобы начать сначала. Вызов итератора повторно после преждевременной остановки может продолжить поток, но вызов его повторно после того, как последовательность завершена, не вернёт никаких значений вообще. В документации функций или методов, возвращающих итераторы одноразового использования, следует указать этот факт:

// Lines returns an iterator over lines read from r.
// It returns a single-use iterator.
func (r *Reader) Lines() iter.Seq[string]

Извлечение значений

Функции и методы, принимающие или возвращающие итераторы, должны использовать стандартные типы Seq или Seq2, чтобы обеспечить совместимость с циклами range и другими адаптерами итераторов. Стандартные итераторы можно рассматривать как «итераторы со сдвигом» (push iterators), которые передают значения в функцию yield.

Иногда цикл range не является наиболее естественным способом потребления значений последовательности. В этом случае Pull преобразует стандартный итератор со сдвигом в «итератор с подтягиванием» (pull iterator), который можно вызывать, чтобы извлекать по одному значению за раз из последовательности. Pull запускает итератор и возвращает пару функций — next и stop — которые возвращают следующее значение из итератора и останавливают его соответственно.

Например:

// Pairs returns an iterator over successive pairs of values from seq.
func Pairs[V any](seq iter.Seq[V]) iter.Seq2[V, V] {
	return func(yield func(V, V) bool) {
		next, stop := iter.Pull(seq)
		defer stop()
		for {
			v1, ok1 := next()
			if !ok1 {
				return
			}
			v2, ok2 := next()
			// If ok2 is false, v2 should be the
			// zero value; yield one last pair.
			if !yield(v1, v2) {
				return
			}
			if !ok2 {
				return
			}
		}
	}
}

Если клиенты не потребляют последовательность до завершения, они должны вызвать stop, что позволяет функции-итератору завершиться и вернуть значение. Как показано в примере, стандартным способом обеспечения этого является использование defer.

Использование стандартной библиотеки

Несколько пакетов в стандартной библиотеке предоставляют API на основе итераторов, в первую очередь пакеты maps и slices. Например, maps.Keys возвращает итератор по ключам карты, а slices.Sorted собирает значения итератора в срез, сортирует их и возвращает срез, таким образом, чтобы пройти по отсортированным ключам карты:

for _, key := range slices.Sorted(maps.Keys(m)) {
	...
}

Изменение

Итераторы предоставляют только значения последовательности, а не прямой способ её изменения. Если итератор хочет предоставить механизм для изменения последовательности во время итерации, обычный подход заключается в определении типа позиции с дополнительными операциями, а затем предоставлении итератора по позициям.

Например, реализация дерева может предоставить:

// Positions returns an iterator over positions in the sequence.
func (t *Tree[V]) Positions() iter.Seq[*Pos]

// A Pos represents a position in the sequence.
// It is only valid during the yield call it is passed to.
type Pos[V any] struct { ... }

// Pos returns the value at the cursor.
func (p *Pos[V]) Value() V

// Delete deletes the value at this point in the iteration.
func (p *Pos[V]) Delete()

// Set changes the value v at the cursor.
func (p *Pos[V]) Set(v V)

А затем клиент может удалить скучные значения из дерева, используя:

for p := range t.Positions() {
	if boring(p.Value()) {
		p.Delete()
	}
}

Индекс

  • func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func())
  • func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func())
  • тип Seq
  • тип Seq2

Файлы пакета

iter.go

func Pull

func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func())

Pull преобразует итератор последовательности seq «стиля push» в итератор «стиля pull», к которому можно получить доступ с помощью двух функций next и stop.

Next возвращает следующее значение в последовательности и логическое значение, указывающее, является ли значение допустимым. Когда последовательность заканчивается, next возвращает нулевое значение V и false. Действительно вызвать next после достижения конца последовательности или после вызова stop. Эти вызовы будут продолжать возвращать нулевое значение V и false.

Stop завершает итерацию. Он должен вызываться, когда вызывающий объект больше не заинтересован в значениях next, и next ещё не сигнализировал о конце последовательности (с возвращаемым логическим значением false). Можно вызывать stop несколько раз и когда next уже вернул false. Обычно вызывающие объекты должны использовать «defer stop()».

Ошибка возникает при вызове next или stop из нескольких горутин одновременно.

Если итератор вызывает ошибку во время вызова next (или stop), то сам next (или stop) вызывает ошибку с тем же значением.

func Pull2

func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func())

Pull2 преобразует итератор последовательности seq «стиля push» в итератор «стиля pull», к которому можно получить доступ с помощью двух функций next и stop.

Next возвращает следующую пару в последовательности и логическое значение, указывающее, является ли пара допустимой. Когда последовательность заканчивается, next возвращает пару нулевых значений и false. Действительно вызвать next после достижения конца последовательности или после вызова stop. Эти вызовы будут продолжать возвращать пару нулевых значений и false.

Stop завершает итерацию. Он должен вызываться, когда вызывающий объект больше не заинтересован в значениях next, и next ещё не сигнализировал о конце последовательности (с возвращаемым логическим значением false). Можно вызывать stop несколько раз и когда next уже вернул false. Обычно вызывающие объекты должны использовать «defer stop()».

Ошибка возникает при вызове next или stop из нескольких горутин одновременно.

Если итератор вызывает ошибку во время вызова next (или stop), то сам next (или stop) вызывает ошибку с тем же значением.

тип Seq

Seq — это итератор по последовательностям отдельных значений. При вызове в качестве seq(yield), seq вызывает yield(v) для каждого значения v в последовательности, останавливаясь раньше, если yield возвращает false. См. документацию пакета iter для получения дополнительной информации.

type Seq[V any] func(yield func(V) bool)

тип Seq2

Seq2 — это итератор по последовательностям пар значений, чаще всего пар ключ-значение. При вызове в качестве seq(yield), seq вызывает yield(k, v) для каждой пары (k, v) в последовательности, останавливаясь раньше, если yield возвращает false. См. документацию пакета iter для получения дополнительной информации.

type Seq2[K, V any] func(yield func(K, V) bool)

© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/iter/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API