当前位置: 首页 > article >正文

【go从零单排】迭代器(Iterators)

挪威特罗姆瑟夜景

🌈Don’t worry , just coding!
内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。

📗概念

在 Go 语言中,迭代器的实现通常不是通过语言内置的迭代器类型,而是通过自定义类型和方法来实现的。下面是一个简单的示例,展示如何在 Go 中实现一个迭代器。

💻代码

迭代器

package main

import "fmt"

// IntSliceIterator 是一个自定义的迭代器,用于迭代整数切片
type IntSliceIterator struct {
	//data:存储要迭代的整数切片。
	//index:当前迭代的位置。
	data  []int
	index int
}

// 定义NewIntSliceIterator函数,输入data切片类型为int
// 返回一个指向 IntSliceIterator 结构体的指针。
func NewIntSliceIterator(data []int) *IntSliceIterator {
	//&IntSliceIterator{} 创建了一个新的 IntSliceIterator 实例并返回
	return &IntSliceIterator{
		data:  data,
		index: 0,
	}
}

// HasNext 检查是否还有下一个元素
func (it *IntSliceIterator) HasNext() bool {
	return it.index < len(it.data)
}

// 定义Next函数 返回下一个元素并移动迭代器
// 输入*IntSliceIterator指针,赋值给it变量
// 返回一个int类型
func (it *IntSliceIterator) Next() int {
	if !it.HasNext() {
		//如果没有更多元素,使用 panic 抛出一个错误
		panic("No more elements")
	}
	//从data 切片中获取当前索引 it.index 指向的元素,并将其赋值给 value。
	value := it.data[it.index]
	//将 index 增加 1,下次调用时指向下一个元素。
	it.index++
	return value
}

func main() {
	data := []int{1, 2, 3, 4, 5}
	iterator := NewIntSliceIterator(data)

	for iterator.HasNext() {
		fmt.Println(iterator.Next())
	}
}

//输出
//1
//2
//3
//4
//5

yeild

在python中yeild表示本次执行结束并返回值,类似于return,yeild和return不同的地方在于yeild可以优雅的返回每次调用时的值。
在go中没有yeild关键字,我们用yeild方便理解。

package main

import (
	"fmt"
	"iter"
	"slices"
)

// 这不是来了么,定义一个泛型List 任意类型的struct
type List[T any] struct {
	head, tail *element[T]
}

// 老样子,定义element泛型struct 任意类型,是一个链表
type element[T any] struct {
	next *element[T]
	val  T
}

// 链表的push方法
func (lst *List[T]) Push(v T) {
	if lst.tail == nil {
		lst.head = &element[T]{val: v}
		lst.tail = lst.head
	} else {
		lst.tail.next = &element[T]{val: v}
		lst.tail = lst.tail.next
	}
}

// 输入为lst,类型为 *List[T],返回一个函数,这个函数的类型是 iter.Seq[T],是一个迭代器
func (lst *List[T]) All() iter.Seq[T] {
	//返回值是一个匿名函数,接受一个参数 yield,这个参数是一个函数类型,接受一个类型为 T 的参数并返回一个布尔值
	return func(yield func(T) bool) {
		//初始化 e 为链表的头节点
		//循环条件为 e != nil
		//e = e.next 将e指向链表下一个节点
		for e := lst.head; e != nil; e = e.next {
			//调用yield,如果yield 返回 false,则退出循环,结束遍历
			if !yield(e.val) {
				return
			}
		}
	}
}

// 斐波那契数列生成
// 定义函数genFib
// 输入参数没有
// 返回一个函数 int类型
func genFib() iter.Seq[int] {
	//返回一个匿名函数func,该匿名函数接受一个参数 yield,这个参数是一个函数类型,接受一个 int 类型的参数并返回一个布尔值。
	return func(yield func(int) bool) {
		//赋值
		a, b := 1, 1
		//调用yield,如果yield 返回 false,则退出循环
		for {
			if !yield(a) {
				return
			}
			a, b = b, a+b
		}
	}
}

func main() {
	lst := List[int]{}
	lst.Push(10)
	lst.Push(13)
	lst.Push(23)

	for e := range lst.All() {
		fmt.Println(e)
	}
	//lst 是一个链表,调用 All() 方法会返回一个迭代器
	//这个生成器会遍历链表中的所有元素,并通过 yield 函数逐个返回这些元素。
	all := slices.Collect(lst.All()) //slices.Collect(...) 函数遍历生成器,收集所有元素
	fmt.Println("all:", all)
	//调用genFib,赋值给n
	for n := range genFib() {
		//当n>=10跳出循环
		if n >= 10 {
			break
		}
		fmt.Println(n)
	}
}

//输出
//10
//13
//23
//all: [10 13 23]
//1
//1
//2
//3
//5
//8

💡 Tips小知识点

迭代器和生成器

在 Go 语言中,生成器和迭代器是处理序列数据的两种不同概念,虽然它们有相似之处,但在实现和使用上有一些关键的区别。

  • 生成器是一种函数,它可以逐步生成一系列值,而不是一次性返回所有值。生成器通常使用 yield 关键字(在 Go 中通常通过返回一个函数来模拟)来返回下一个值,并保持其状态,以便在下一次调用时继续执行。
  • 生成器通常在需要时生成值,适用于需要惰性求值的场景。调用生成器时,可以获取下一个值,而不需要事先知道所有值。
  • 生成器通过闭包保持状态,允许在多次调用之间保留局部变量的值。
  • 迭代器是一种对象,它实现了特定的接口(通常包含 Next() 方法),用于遍历集合中的元素。迭代器维护一个内部状态,允许用户逐步访问集合的每个元素。
  • 迭代器通常用于遍历整个集合,通过调用 Next() 方法来获取下一个元素,直到没有更多元素可供访问。
  • 迭代器通过结构体的字段来管理状态,通常在结构体中维护当前元素的指针或索引。

生成器Example

func genFib() func() int {
    a, b := 0, 1
    return func() int {
        a, b = b, a+b
        return a
    }
}

迭代器Example

type Iterator struct {
    current *Node
}

func (it *Iterator) Next() *Node {
    if it.current == nil {
        return nil
    }
    node := it.current
    it.current = it.current.next
    return node
}

💪无人扶我青云志,我自踏雪至山巅。
在这里插入图片描述


http://www.kler.cn/a/387996.html

相关文章:

  • 《MYSQL45讲》误删数据怎么办
  • POI实现根据PPTX模板渲染PPT
  • AMD CPU下pytorch 多GPU运行卡死和死锁解决
  • Linux 进程线程间通信总结
  • Unity3D学习FPS游戏(11)敌人AI巡逻(NavMesh)
  • 【MySQL从入门到放弃】InnoDB磁盘结构(一)
  • chrony服务器(linux)
  • w029基于springboot的网上购物商城系统研发
  • Kubernetes中的statefulset控制器
  • 构建智能防线 灵途科技光电感知助力轨交全向安全防护
  • 现代Web开发:React Hooks深入解析
  • 鸿蒙移动应用开发-------初始arkts
  • php 之添加图片水印,根据比例计算水印的新尺寸
  • ssm080削面快餐店点餐服务系统的设计与实现+jsp(论文+源码)_kaic
  • 在IDEA中使用Git
  • Unity——鼠标点击信息和当前位置获取
  • Java 处理 json 格式数据解析为 csv 格式
  • 在React项目中配置@作为路径别名
  • 企业资产管理:SpringBoot技术实践
  • 安卓智能指针sp、wp、RefBase浅析
  • vue3学习:查询城市天气预报案例(vite组合式实现)
  • 【docker】6. 镜像仓库/镜像概念
  • 【前端】Svelte:组件间通信
  • Mac如何实现最简单的随时监测实时运行状态的方法
  • 【Homework】【1--4】Learning resources for DQ Robotics in MATLAB
  • 24/11/5 算法笔记 DBSCAN聚类算法