# 05.9.3 使用 container/ring

这一节中将使用 `conRing.go` 中的 Go 语言代码阐述 `container/ring` 包的用法，下面分为四个部分介绍。注意，`container/ring` 比 `container/list` 和 `container/heap` 都简单多了，也就是说这个包中的函数比另外两个包中的要少一些。

`conRing.go` 中的第一个代码段如下：

```go
package main

import (
    "container/ring"
    "fmt"
)

var size int = 10
```

`size` 变量存储了要创建的环的大小。

`conRing.go` 的第二部分包含如下 Go 代码：

```go
func main() {
    myRing := ring.New(size + 1)
    fmt.Println("Empty ring:", *myRing)

    for i := 0; i < myRing.Len()-1; i++ {
        myRing.Value = i
        myRing = myRing.Next()
    }

    myRing.Value = 2
```

从上面可知，创建新的环需要使用 `ring.New()` 函数，它需要接受一个提供环的大小的参数。最后的 `myRing.Value = 2` 语句向环中加入了 2 这个值。不过前面的 `for` 循环中已经向环中加入了那个值。最后，环的零值指的是只有一个值为 `nil` 的元素的环。

`conRing.go` 的第三部分如下：

```go
    sum := 0
    myRing.Do(func(x interface{}) {
        t := x.(int)
        sum = sum + t
    })
    fmt.Println("Sum:", sum)
```

`ring.Do()` 函数可以对环上的每个元素依次调用一个函数。然而 `ring.Do()` 没有定义对环进行修改的行为。`x.(int)` 语句称为**类型断言**。第 7 章“反射和接口”中将详细介绍类型断言。目前，你只用知道这表示 `x` 是 `int` 类型的就行了。

`conRing.go` 的最后一部分程序如下：

```go
    for i := 0; i < myRing.Len()+2; i++ {
        myRing = myRing.Next()
        fmt.Print(myRing.Value, " ")
    }
    fmt.Println()
}
```

使用环会遇到的唯一的问题就是你可以无限调用 `ring.Next()`，所以你需要找到停下来的办法。这种情况下就需要用到 `ring.Len()` 函数。就个人而言，我比较倾向于使用 `ring.Do()` 函数来迭代环上的所有元素，因为这样代码更简洁，但用 `for` 循环其实也不错！

执行 `conRing.go` 将会生成如下输出：

```bash
$ go run conRing.go
Empty ring: {0x42000a080 0xc42000a1a0 <nil>}
Sum: 47
0 1 2 3 4 5 6 7 8 9 2 0 1
```

输出的结果证明环上可以存在重复的值，也就是说你只能通过 `ring.Len()` 函数才能安全地获取到环的大小。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wskdsgcf.gitbook.io/mastering-go-zh-cn/05.0/05.9/05.9.3.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
