当前位置:首页 > 文章列表 > Golang > Go教程 > Go 怎么让自定义集合支持 for range 遍历

Go 怎么让自定义集合支持 for range 遍历

来源:17golang原创 2026-09-06 08:05:25 0浏览 收藏

如果一个集合把内部 map 或切片直接暴露出来,调用方很快就会依赖存储细节。更合适的做法是给集合提供一个返回 iter.Seq[T] 的 All 方法:集合自己决定怎样产出元素,调用方仍然可以写出熟悉的 for v := range set.All()。

在支持 range-over-function 的 Go 版本中,自定义集合只要返回 iter.Seq[T],并在闭包中逐个调用 yield,就能直接被 for range 遍历;当 yield 返回 false 时,集合应立即停止当前遍历。
要点速览
  • iter.Seq[T] 的形状是 func(yield func(T) bool)。
  • 集合通常用 All() iter.Seq[T] 隐藏内部存储。
  • 调用方的 break 会让后续 yield 返回 false,闭包必须尊重这个信号。

先确认 iter.Seq 为什么能接上 for range

这不是给 for range 增加一个集合接口,而是利用 Go 1.23 引入的函数类型遍历能力。标准库 iter 把单值序列定义成:

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

也就是说,集合返回的不是已经准备好的切片,而是一个“接收回调并产生值”的函数。range 负责提供回调,集合负责在合适的时候调用它。这个协议同时保留了提前结束的语义,比让调用方读取内部 map 更适合做包级 API。

把集合遍历协议写成 iter.Seq

下面用泛型集合保存唯一值。示例只关心遍历协议,集合的新增和查询方法保持简单:

package main

import (
    "fmt"
    "iter"
)

// Set 保存不重复的元素,内部 map 不暴露给调用方。
type Set[T comparable] struct {
    items map[T]struct{}
}

// NewSet 创建一个可以直接写入的集合。
func NewSet[T comparable]() *Set[T] {
    return &Set[T]{items: make(map[T]struct{})}
}

// Add 把元素放入集合,重复值不会产生第二份数据。
func (s *Set[T]) Add(v T) {
    s.items[v] = struct{}{}
}

// All 返回集合的单值迭代器,方法名表达“所有元素”。
func (s *Set[T]) All() iter.Seq[T] {
    return func(yield func(T) bool) {
        for v := range s.items {
            // false 表示调用方不再需要后续元素。
            if !yield(v) {
                return
            }
        }
    }
}

func main() {
    set := NewSet[string]()
    set.Add("go")
    set.Add("range")

    // 调用方不需要知道集合内部使用了 map。
    for v := range set.All() {
        fmt.Println(v)
    }
}

All 每次调用都创建一个新的闭包,闭包再读取当前集合内容。调用方只依赖 iter.Seq[T],因此以后把内部 map 换成树或其他结构,遍历 API 仍然可以保持不变。

Go 自定义集合中 Set、内部 map、All 方法、iter.Seq 与 for range 调用方的静态边界关系
图1:自定义集合通过 All 返回 iter.Seq,把内部 map 与调用方的 for range 解耦。

调用方用 for range 消费,并正确处理中途停止

遍历接口最容易遗漏的是提前停止。调用方发现目标值后可以直接 break,此时迭代器收到的 yield 结果会变成 false。因此 All 里的判断不能省略,否则集合仍可能继续做无意义的工作。

// Find 返回第一个满足条件的元素。
func Find[T comparable](set *Set[T], want T) (T, bool) {
    // zero 用于没有命中时的返回值。
    var zero T
    for v := range set.All() {
        if v == want {
            return v, true
        }
    }
    return zero, false
}

这里不需要自己调用 iter.Pull。只有当消费方不适合写成 range,需要逐个调用 next 时,才考虑把 push 风格的序列转换成 pull 风格,并用 defer stop() 收尾。

Go iter.Seq 中 range consumer、break 条件、yield bool 与 All 闭包之间的提前停止和重复遍历关系
图2:调用方的 break 通过 yield 的 false 语义终止当前遍历,All 每次返回新的闭包以支持再次遍历。

空集合、重复遍历和 API 命名怎么定

空集合不需要特殊分支:内部 range 不进入循环,序列自然结束。一个普通的 All 也应支持重复调用;如果底层是不可回退的文件流或网络流,就要在文档中明确标注“单次使用”,避免调用方误以为每次都能从头开始。

设计点建议原因
单值集合All() iter.Seq[T]与常见 range 写法一致
键值序列Scan() iter.Seq2[K, V]保留 key 和 value 的配对关系
多种顺序用 Backward 等名字区分把顺序写进 API,而不是藏在实现里
中途停止检查 yield 的 bool让 break 真正停止底层遍历

相关问题

自定义集合一定要叫 All 吗?

不强制,但 All 是集合返回全部元素时的常用约定。若方法只返回城市、倒序元素或过滤结果,使用能表达序列内容的名字更清楚。

iter.Seq 可以修改集合元素吗?

它本身只提供值。需要在遍历中修改时,可以让迭代器返回位置对象,再由位置对象提供受控的修改方法。

为什么不直接返回切片?

切片会暴露快照、复制或内部存储的选择;iter.Seq 让集合保留遍历实现权,也能自然响应提前停止。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python sqlite3 批量写入怎么控制提交和回滚Python sqlite3 批量写入怎么控制提交和回滚
上一篇
Python sqlite3 批量写入怎么控制提交和回滚
人类基准反应测试测的是什么?反应时间计算、设备延迟与结果解读
下一篇
人类基准反应测试测的是什么?反应时间计算、设备延迟与结果解读
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    575次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    617次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    649次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    609次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    424次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码