range по функциям
В Go 1.23 (запланирован в августе) появится цикл range по функциям. Проще всего показать на примере.
Допустим, мы написали функцию, которая принимает срез, и возвращает его инвертированную версию, не меняя при этом оригинал:
func Backward[E any](s []E) []E {
r := make([]E, 0, len(s))
for i := len(s) - 1; i >= 0; i-- {
r = append(r, s[i])
}
return r
}
Пример использования:
s := []string{"a", "b", "c"}
for _, el := range Backward(s) {
fmt.Print(el, " ")
}
// c b a
И все бы хорошо, но Backward создает копию исходного среза. Для abc это не проблема, но в целом не слишком-то эффективно с точки зрения использования памяти.
В идеале мы бы хотели итерироваться по оригинальному срезу в обратном порядке, не создавая новый срез.
С range по функциям это можно сделать. Следите за руками:
func Backward[E any](s []E) func(func(int, E) bool) {
return func(yield func(int, E) bool) {
for i := len(s) - 1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
}
}
Пример использования:
s := []string{"a", "b", "c"}
for _, el := range Backward(s) {
fmt.Print(el, " ")
}
// c b a
Вы можете поинтересоваться, какого черта мы вообще этим занимаемся. Ведь можно сделать обычный цикл, обходящий s в обратном порядке, да и все дела.
Напишу об этом отдельно.
В Go 1.23 (запланирован в августе) появится цикл range по функциям. Проще всего показать на примере.
Допустим, мы написали функцию, которая принимает срез, и возвращает его инвертированную версию, не меняя при этом оригинал:
func Backward[E any](s []E) []E {
r := make([]E, 0, len(s))
for i := len(s) - 1; i >= 0; i-- {
r = append(r, s[i])
}
return r
}
Пример использования:
s := []string{"a", "b", "c"}
for _, el := range Backward(s) {
fmt.Print(el, " ")
}
// c b a
И все бы хорошо, но Backward создает копию исходного среза. Для abc это не проблема, но в целом не слишком-то эффективно с точки зрения использования памяти.
В идеале мы бы хотели итерироваться по оригинальному срезу в обратном порядке, не создавая новый срез.
С range по функциям это можно сделать. Следите за руками:
func Backward[E any](s []E) func(func(int, E) bool) {
return func(yield func(int, E) bool) {
for i := len(s) - 1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
}
}
Пример использования:
s := []string{"a", "b", "c"}
for _, el := range Backward(s) {
fmt.Print(el, " ")
}
// c b a
Вы можете поинтересоваться, какого черта мы вообще этим занимаемся. Ведь можно сделать обычный цикл, обходящий s в обратном порядке, да и все дела.
Напишу об этом отдельно.