🔄 Range Over Functions: Quick Start
Уже стал доступен первый Release Candidate Go 1.23, который вносит в язык синтаксический сахар в виде итераторов, наконец не в experiment.
Этот пост — быстрый тур в грядущее обновление
Цель: стандартизация
Сама фича позволяет нам теперь в качестве аргумента оператора range использовать функцию, имеющую следующие сигнатуры
func(yield func() bool)
func(yield func(K) bool)
func(yield func(K, V) bool)
(название аргумента, конечно же, может быть любым)
При создании конструктора, чтобы не прописывать трудно читаемый тип возвращаемой функции, можно использовать iter.Seq[T] и iter.Seq2[T]
Легче всего понять что и как на примере.
Вот пример функции
package slices
import "iter"
func Backward[E any](s []E) iter.Seq2[int, E] {
return func(yield func(int, E) bool) {
for i := len(s)-1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
}
}
Вот пример использования
s := []string{"hello", "world"}
for i, x := range slices.Backward(s) {
fmt.Println(i, x)
}
Тем временем компилятор заменит код следующим образом:
slices.Backward(s)(func(i int, x string) bool {
fmt.Println(i, x)
return true
})
Становится понятно, что никакой магии здесь нет. Тело цикла попадает в виде функции-аргумента (yield) в функцию-итератор. Если внутри цикла встречается break — yield возвращает false и итерацию нужно прекратить. В противном случае будет паника.
Собственно, этой информации вам будет достаточно, чтобы писать свои итераторы. Вот набор ссылок по теме:
* 1.23rc1 Release Notes
* Issue с "мотивацией"
* Go Wiki: RangeOverFunctions Experiment
* Proposal of iter library (С чего всё началось)
* go iter package
Уже стал доступен первый Release Candidate Go 1.23, который вносит в язык синтаксический сахар в виде итераторов, наконец не в experiment.
Этот пост — быстрый тур в грядущее обновление
Цель: стандартизация
Сама фича позволяет нам теперь в качестве аргумента оператора range использовать функцию, имеющую следующие сигнатуры
func(yield func() bool)
func(yield func(K) bool)
func(yield func(K, V) bool)
(название аргумента, конечно же, может быть любым)
При создании конструктора, чтобы не прописывать трудно читаемый тип возвращаемой функции, можно использовать iter.Seq[T] и iter.Seq2[T]
Легче всего понять что и как на примере.
Вот пример функции
package slices
import "iter"
func Backward[E any](s []E) iter.Seq2[int, E] {
return func(yield func(int, E) bool) {
for i := len(s)-1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
}
}
Вот пример использования
s := []string{"hello", "world"}
for i, x := range slices.Backward(s) {
fmt.Println(i, x)
}
Тем временем компилятор заменит код следующим образом:
slices.Backward(s)(func(i int, x string) bool {
fmt.Println(i, x)
return true
})
Становится понятно, что никакой магии здесь нет. Тело цикла попадает в виде функции-аргумента (yield) в функцию-итератор. Если внутри цикла встречается break — yield возвращает false и итерацию нужно прекратить. В противном случае будет паника.
Собственно, этой информации вам будет достаточно, чтобы писать свои итераторы. Вот набор ссылок по теме:
* 1.23rc1 Release Notes
* Issue с "мотивацией"
* Go Wiki: RangeOverFunctions Experiment
* Proposal of iter library (С чего всё началось)
* go iter package