ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

lo 库 FindDuplicatesByErr 详解:基于 iteratee 键值查找重复元素并支持错误中止

lo 库 FindDuplicatesByErr 详解:基于 iteratee 键值查找重复元素并支持错误中止 lo 库 FindDuplicatesByErr 详解基于 iteratee 键值查找重复元素并支持错误中止【免费下载链接】lo A Lodash-style Go library based on Go 1.18 Generics (map, filter, contains, find...)项目地址: https://gitcode.com/GitHub_Trending/lo/lo导读FindDuplicatesByErr是 loLodash-style 的 Go 泛型库find 子模块中一个可出错版的去重查找助手它借助用户提供的iteratee函数把任意类型元素映射为可比较的键key返回每个重复键在集合中首次出现的那一个元素并保持原始顺序同时iteratee可以返回error一旦出错迭代立即中止、函数直接返回该错误。本文以 core-findduplicatesbyerr.md 文档为核心结合 find.go 的源码实现与 find_test.go 的测试用例从签名、用法、错误语义、内部两趟扫描原理、与同类助手的对比到类型保持特性给出完整可落地的实战指南。函数签名与类型约束func FindDuplicatesByErr[T any, U comparable, Slice ~[]T](collection Slice, iteratee func(item T) (U, error)) (Slice, error)参数与返回值说明成员含义collection Slice输入集合Slice ~[]T表示既接受标准切片[]T也接受任何以[]T为底层类型的具名切片类型见下方类型保持一节iteratee func(item T) (U, error)对每个元素调用的键生成函数把T映射为用于判定重复的键U同时可附带错误U comparable键类型必须可比较因为内部需要用map[U]bool记录已见状态返回值(Slice, error)正常时返回重复元素切片与nil出错时返回nil切片与错误从源码结构看该函数与 FindDuplicatesBy文档是错误处理变体关系FindDuplicatesBy的iteratee只返回键而FindDuplicatesByErr让iteratee额外返回error从而在无法继续计算键如外部 API 调用失败、数据非法时拥有提前终止的能力。基本用法按键查找重复元素文档给出的典型示例对应源码第 445-489 行实现如下result, err : lo.FindDuplicatesByErr([]int{3, 4, 5, 6, 7}, func(i int) (int, error) { return i % 3, nil }) // []int{3, 4}, nil执行过程逐步拆解依次计算键3 % 3 0、4 % 3 1、5 % 3 2、6 % 3 0、7 % 3 1键0与1各出现两次属于重复键键2只出现一次结果取每个重复键在集合中首次出现的元素键0首次对应3键1首次对应4且结果保持原始顺序因此得到[]int{3, 4}。要点返回的不是全部重复元素那会得到{3, 4, 6, 7}而是每个重复键的代表元素其顺序由元素在集合中首次出现的位置决定。错误处理语义迭代立即中止iteratee返回错误时函数的行为在文档中有明确示例result, err : lo.FindDuplicatesByErr([]int{3, 4, 5, 6, 7}, func(i int) (int, error) { if i 5 { return 0, fmt.Errorf(number 5 is not allowed) } return i % 3, nil }) // []int(nil), error(number 5 is not allowed)关键语义有三点均与源码实现一一对应立即中止源码在第一趟统计find.go与第二趟收集find.go中都检查了err ! nil任一阶段出错都直接return返回 nil 切片出错分支执行var result Slice; return result, err即返回零值nil切片绝不返回部分结果造成误判两趟都会触发由于实现分两趟扫描集合第二趟中iteratee出错同样会中止并返回错误。测试 find_test.go 专门用回调计数器验证了提前中止契约错误发生在第一趟第 0 个元素iteratee只被调用 1 次错误发生在第一趟第 2 个元素调用 3 次后中止错误发生在第二趟首个元素输入{3, 4, 5, 6}、errorAt3第一趟完整执行 4 次后第二趟在第一个元素处出错总调用次数为 4注释明确说明error at first item of second pass。测试同时断言出错时返回值为nilis.Nil(result, nil should be returned on error)。源码原理两趟扫描 map 状态机FindDuplicatesByErr的实现find.go采用统计 收集两趟扫描与FindDuplicatesBy的findDuplicatesByLarge路径共享同一套 map 状态机思路第一趟统计键的出现次数状态isDupl : make(map[U]bool, len(collection)) duplicates : 0 for i : range collection { key, err : iteratee(collection[i]) if err ! nil { var result Slice return result, err } duplicated, seen : isDupl[key] if !duplicated { isDupl[key] seen if seen { duplicates } } }这里map[U]bool的布尔值记录该键是否为重复键键第一次遇到时记录false未重复第二次遇到时变为true并累加duplicates计数之后保持true不再变化。duplicates用于预分配结果切片容量make(Slice, 0, duplicates)避免收集阶段反复扩容。第二趟按顺序收集首次出现的重复元素result : make(Slice, 0, duplicates) for i : range collection { key, err : iteratee(collection[i]) if err ! nil { var result Slice return result, err } if duplicated : isDupl[key]; duplicated { result append(result, collection[i]) isDupl[key] false } } return result, nil再次扫描集合当某元素的键被标记为重复时将其收入结果并把该键标记重置为false从而确保同一重复键只输出首次出现的元素。需要特别指出的实现事实iteratee在每一趟都会对每个元素重新调用一次两趟共调用约 2×N 次出错时提前中止这与findDuplicatesBySmall中先预计算 keys 再复用的实现不同后者将调用次数严格限制为每元素一次见 find.go。因此如果iteratee有副作用或开销较大应留意FindDuplicatesByErr的调用次数特征。无错误时与 FindDuplicatesBy 行为等价把iteratee固定返回(key, nil)时FindDuplicatesByErr与 FindDuplicatesBy 的输出完全一致。二者的定位差异可总结为对比项FindDuplicatesByFindDuplicatesByErriteratee 签名func(item T) Ufunc(item T) (U, error)错误处理无键计算失败无从感知出错立即中止并返回(nil, err)典型场景键计算是纯函数、不会失败键计算可能出错解析、查库、网络请求等测试 find_test.go 覆盖了正常路径的四类输入发现重复{3,4,5,6,7}→{3,4}、无重复{0,1,2,3,4}→{0,1}、空集合{}→{}、全部重复{0,3,6,9}→{0}。其中无重复场景值得注意当所有键都唯一时第一趟结束后duplicates 0第二趟不会收集任何元素结果为空切片而非 nil。实战类型保持Named Slice Type由于签名使用Slice ~[]T约束FindDuplicatesByErr会保持传入的具名切片类型而非退化为[]T。测试 find_test.go 验证了这一点type myStrings []string allStrings : myStrings{a, b, a, c, b} result, err : FindDuplicatesByErr(allStrings, func(s string) (string, error) { return s, nil }) is.NoError(err) is.IsType(result, allStrings, type preserved) // 返回值仍是 myStrings 类型这在用类型别名携带业务语义如type OrderIDs []int64的项目中非常实用无需手动做类型断言或转换。与同类助手的选型建议在 lo 的 find 子模块中围绕重复/唯一有一组定位互补的助手可参考文档目录 docs/data 下的core-findduplicates*.md、core-finduniques*.mdFindDuplicates实现元素本身可比较时直接判重无需iterateeFindDuplicatesBy实现按iteratee生成的键判重不可出错FindDuplicatesByErr本文主角按键判重且键计算过程可出错并提前终止FindUniques / FindUniquesBy实现 / 实现语义相反返回只出现一次的唯一元素其中小集合路径还专门设计了避免 map 分配的线性扫描实现findUniquesBySmall见 find.go。选型建议键计算是纯函数 → 用FindDuplicatesBy即可性能更好、签名更简单键计算可能失败如解析用户输入、调用外部服务→ 必须用FindDuplicatesByErr把错误显式传递出来元素本身可比较 → 直接用FindDuplicates省去一层映射。延伸阅读完整实现find.goFindDuplicatesByErr、find.goFindDuplicatesBy及其大小集合路径测试用例find_test.go正常路径、错误中止路径、类型保持三组表驱动测试相关文档core-findduplicatesby.md、core-findduplicates.md、core-finduniquesby.mdfind 子模块的完整能力清单可参阅 docs/docs/core/find.md基准测试见 benchmark/core_find_bench_test.go其中BenchmarkFindDuplicatesBy使用v % 50作为键进行压测【免费下载链接】lo A Lodash-style Go library based on Go 1.18 Generics (map, filter, contains, find...)项目地址: https://gitcode.com/GitHub_Trending/lo/lo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表