ZetCode

Golang 切片.Backward

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 `slices.Backward` 函数。我们将通过实际示例涵盖切片的反向迭代。

`slices.Backward` 函数提供了一种按反向顺序迭代切片的方法。它是 Go 实验性切片包的一部分。

当您需要从后向前处理元素时,此函数非常有用。它返回一个迭代器,该迭代器从末尾开始产生元素。

基本 slices.Backward 示例

`slices.Backward` 最简单的用法是按反向顺序打印数字。我们创建一个迭代器并遍历它。

basic_backward.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{1, 2, 3, 4, 5}
    
    for it := slices.Backward(numbers); ; {
        num, ok := it.Next()
        if !ok {
            break
        }
        fmt.Println(num)
    }
}

我们为数字切片创建了一个反向迭代器。循环继续,直到 `Next()` 返回 false,打印从 5 到 1 的元素。

反向处理字符串

`slices.Backward` 可以反向迭代字符串切片。此示例从后向前打印单词。

string_backward.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    words := []string{"apple", "banana", "cherry"}
    
    for it := slices.Backward(words); ; {
        word, ok := it.Next()
        if !ok {
            break
        }
        fmt.Println(word)
    }
}

迭代器首先产生“cherry”,然后是“banana”,最后是“apple”。这展示了如何反向处理字符串元素。

在迭代期间修改元素

我们可以在反向迭代期间修改切片元素。此示例在向后移动时将每个数字加倍。

modify_backward.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{1, 2, 3, 4, 5}
    
    for it := slices.Backward(numbers); ; {
        num, ok := it.Next()
        if !ok {
            break
        }
        *num *= 2
    }
    
    fmt.Println("Modified slice:", numbers)
}

迭代器返回元素的指针,从而允许修改。迭代后,切片变为 [2, 4, 6, 8, 10]。

与其他切片函数结合使用

`slices.Backward` 可以与其他切片操作结合使用。此示例在反向迭代时过滤偶数。

combined_backward.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{1, 2, 3, 4, 5, 6}
    var evens []int
    
    for it := slices.Backward(numbers); ; {
        num, ok := it.Next()
        if !ok {
            break
        }
        if *num%2 == 0 {
            evens = append(evens, *num)
        }
    }
    
    fmt.Println("Even numbers in reverse:", evens)
}

我们收集反向顺序的偶数。结果是 [6, 4, 2],展示了如何将过滤与反向迭代结合起来。

空切片行为

`slices.Backward` 可以很好地处理空切片。此示例演示了它在空切片上的行为。

empty_backward.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    var empty []string
    
    count := 0
    for it := slices.Backward(empty); ; {
        _, ok := it.Next()
        if !ok {
            break
        }
        count++
    }
    
    fmt.Println("Elements processed:", count)
}

对于空切片,迭代器会立即返回 false。不处理任何元素,计数器保持为零。

性能注意事项

反向迭代具有与前向迭代相同的性能特征。此示例对反向与前向迭代进行了基准测试。

performance_backward.go
package main

import (
    "fmt"
    "slices"
    "time"
)

func main() {
    largeSlice := make([]int, 1_000_000)
    for i := range largeSlice {
        largeSlice[i] = i
    }
    
    // Backward iteration
    start := time.Now()
    for it := slices.Backward(largeSlice); ; {
        _, ok := it.Next()
        if !ok {
            break
        }
    }
    fmt.Println("Backward iteration:", time.Since(start))
    
    // Forward iteration
    start = time.Now()
    for _, v := range largeSlice {
        _ = v
    }
    fmt.Println("Forward iteration:", time.Since(start))
}

两种迭代都需要相似的时间,这表明反向迭代不会增加显着的开销。对于大多数用例,差异可以忽略不计。

实际示例:撤销操作

这个实际示例使用反向迭代来实现撤销功能。我们按相反的顺序处理操作以撤销它们。

undo_backward.go
package main

import (
    "fmt"
    "slices"
)

type Action struct {
    Name string
    Undo func()
}

func main() {
    actions := []Action{
        {"create", func() { fmt.Println("Undo create") }},
        {"edit", func() { fmt.Println("Undo edit") }},
        {"delete", func() { fmt.Println("Undo delete") }},
    }
    
    fmt.Println("Undoing actions:")
    for it := slices.Backward(actions); ; {
        action, ok := it.Next()
        if !ok {
            break
        }
        action.Undo()
    }
}

撤销操作按相反顺序执行:先删除,然后编辑,然后创建。这演示了反向迭代的真实用例。

来源

Go 实验性切片包文档

本教程通过各种场景下的反向迭代的实际示例,涵盖了 Go 中的 `slices.Backward` 函数。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程