如何减少Go语言中两个分页DB结果迭代器的代码重复?
减少分页迭代器的代码重复:用Go泛型轻松搞定!
嘿,这个问题太典型了——当你有一堆结构几乎一模一样的迭代器时,泛型就是解决代码重复的完美方案!先瞅瞅你代码里的重复点:两个迭代器都有hasNext、app、batchSize字段,New方法和HasNext逻辑完全一致,唯一的区别就是Next里调用的查询方法和返回的模型类型。咱们用Go 1.18+支持的泛型把通用逻辑抽离出来,彻底告别重复代码!
第一步:定义通用泛型迭代器
先写一个通用的分页迭代器结构体,把所有重复的逻辑都塞进去,只把不同的部分(也就是获取分页数据的函数)作为参数传入:
// PageIterator 通用分页迭代器,T代表迭代返回的模型类型 type PageIterator[T any] struct { hasNext bool app *App batchSize int offset int // 注意:原代码里offset每次重置为0是bug,这里改成结构体字段保存偏移量 // fetchFunc 由具体模型的查询逻辑实现,用于获取指定offset和limit的分页数据 fetchFunc func(offset, limit int) []*T } // NewPageIterator 创建通用分页迭代器 func NewPageIterator[T any](app *App, batchSize int, fetchFunc func(offset, limit int) []*T) *PageIterator[T] { return &PageIterator[T]{ hasNext: true, app: app, batchSize: batchSize, offset: 0, fetchFunc: fetchFunc, } } func (it *PageIterator[T]) HasNext() bool { return it.hasNext } func (it *PageIterator[T]) Next() []*T { // 调用传入的查询函数获取当前页数据 batch := it.fetchFunc(it.offset, it.batchSize) // 如果返回的数量小于批次大小,说明没有下一页了 if len(batch) < it.batchSize { it.hasNext = false } // 偏移量累加,准备下一页查询 it.offset += it.batchSize return batch }
第二步:用通用迭代器创建具体的Foo/Bar迭代器
现在你再也不用写FooIterator和BarIterator了,只需要传入对应的查询函数就能快速创建迭代器:
// 创建Foo迭代器 fooIterator := NewPageIterator[model.Foo](a, 100, func(offset, limit int) []*model.Foo { return a.GetAllFoosInPages(offset, limit) }) // 创建Bar迭代器 barIterator := NewPageIterator[model.Bar](a, 100, func(offset, limit int) []*model.Bar { return a.GetAllBarsInPages(offset, limit) })
第三步:使用方式和之前完全一致
原来的循环逻辑不需要任何改动,直接用就行:
for fooIterator.HasNext() { fooBatch := fooIterator.Next() // 处理Foo数据 } for barIterator.HasNext() { barBatch := barIterator.Next() // 处理Bar数据 }
额外提示:修复了原代码的bug
你原来的Next方法里每次都把offset初始化为0,这会导致每次都查询第一页,永远翻不了页。通用迭代器里把offset作为结构体字段保存,每次调用Next后自动累加,这才是正确的分页逻辑哦!
这个方案的好处简直拉满:
- 完全消除了重复代码,所有通用逻辑都在
PageIterator里统一维护 - 后续新增其他模型的分页迭代器(比如Baz),只需要传对应的查询函数就行,不用再写重复的结构体和方法
- 逻辑更清晰,把通用逻辑和具体业务逻辑彻底解耦
内容的提问来源于stack exchange,提问作者user9772923
相关产品推荐
相关产品推荐

