ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hugo 模板函数 collections.Union 完全指南:切片并集与 where 查询 OR 过滤

Hugo 模板函数 collections.Union 完全指南:切片并集与 where 查询 OR 过滤 Hugo 模板函数 collections.Union 完全指南切片并集与 where 查询 OR 过滤【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo导读collections.Union是 Hugo 模板引擎中用于合并两个切片/数组并自动去重的集合运算函数别名union。它不仅是处理页面集合、标签列表等数据去重合并的基础工具更是构建where复杂条件查询时实现OR或语义过滤的关键拼图。读完本文你将掌握union的完整语法、nil 与类型边界处理、底层去重实现原理并能直接用它在 Hugo 站点中组合出类型排除 置顶 必须有封面图等多条件筛选管线。函数签名与基本用法collections.Union的完整调用形式为collections.Union SLICE1 SLICE2官方文档见 docs/content/en/functions/collections/Union.md声明了以下参数元信息项目值别名union返回类型[]any签名collections.Union SLICE1 SLICE2文档别名/functions/union在模板中通常直接使用短别名union它与collections.Union完全等价。最基本的用法如下{{ union (slice 1 2 3) (slice 3 4 5) }} → [1 2 3 4 5]注意输出结果不是简单的拼接[1 2 3 3 4 5]而是将两个切片的元素合并后去除重复项——元素3只出现一次。这一合并 去重语义来自底层intersector实现中基于seen map[any]bool的判重逻辑见 tpl/collections/collections.go只有未出现过的元素才会被追加进结果切片。union同样支持管道pipeline写法这在组合多个过滤条件时尤为常见{{ $all : $first | union $second }}nil 参数的边界行为Hugo 模板中切片变量可能为空或为 nilunion对此有明确且安全的处理策略。官方文档给出的四个边界示例完整如下{{ union (slice 1 2 3) nil }} → [1 2 3] {{ union nil (slice 1 2 3) }} → [1 2 3] {{ union nil nil }} → []从源码看Union 函数实现 首先对两个参数做了 nil 前置判断两个参数都为 nil直接返回空切片[]any{}仅 l1 为 nil原样返回 l2非 nil 一侧仅 l2 为 nil原样返回 l1非 nil 一侧。也就是说单侧为 nil 时并不会报错而是静默返回非空的那一侧这保证了在模板中对可能为空的集合做并集运算时不会中断渲染。这一行为也被单元测试逐条覆盖见 tpl/collections/collections_test.go 中{nil, nil, []any{}, false}、{nil, []string{a, b}, []string{a, b}, false}等用例。源码级解析union 的底层实现原理union的实现位于 tpl/collections/collections.go核心流程可以概括为三步类型检查与反射包装通过reflect.ValueOf获取两个入参的反射值要求双方都必须是数组Array或切片Slice类型否则返回cant iterate over ...错误见源码 default 分支。去重收集构造intersector结构体内含结果切片r与判重集合seen先遍历 l1 追加未见过元素再遍历 l2 追加未见过元素。判重的关键是appendIfNotSeen配合normalizetpl/collections/reflect_helpers.go数字类型会被统一转换为float64后比较因此int(1)、int64(1)、float64(1)视为同一元素不可比较的类型如 map、切片通过哈希值HashUint64参与判重实现了resource.TransientIdentifier接口的资源则用其TransientKey作为判重键。跨类型元素归一化当两个切片元素类型不同但都兼容时字符串通过hreflect.ToStringE转换后追加数字通过convertNumber转换到目标类型后追加见 tpl/collections/collections.go。需要特别指出两个容易踩坑的点类型一致性限制如果 l1 与 l2 的元素类型不同且两者都不是interface{}元素则函数直接返回空切片见 tpl/collections/collections.go。单元测试中{[]string{1, 2}, []int{3}, []string{}, false}即验证了[]string ∪ []int返回空结果。混合类型场景下请确保至少一侧是[]any。不可比较元素报错若切片元素是不可比较类型如[]map[string]int、[][]intunion会返回错误union does not support slices or arrays of uncomparable types见 tpl/collections/collections.go对应测试用例见 tpl/collections/collections_test.go。实战用 union 实现 where 查询的 OR 过滤单靠where只能表达与关系而union的并集语义天然就是或关系。官方文档给出了一个完整的 OR 过滤管线{{ $pages : where .Site.RegularPages Type not in (slice page about) }} {{ $pages $pages | union (where .Site.RegularPages Params.pinned true) }} {{ $pages $pages | intersect (where .Site.RegularPages Params.images ! nil) }}这条管线的逻辑是先取出类型既不是page也不是about的常规页面再通过union并入所有置顶pinned页面——即使置顶页属于被排除的类型也会因为union的或语义重新进入集合最后用intersect过滤掉 Page 参数中没有设置images的页面。拆解每一步第一步where .Site.RegularPages Type not in (slice page about)得到排除指定类型后的基础集合第二步$pages | union (where .Site.RegularPages Params.pinned true)取并集等价于基础集合或置顶页面第三步$pages | intersect (...)再取交集等价于上述结果且必须有 images。三者组合后表达的自然语言是排除 page/about 类型除非被置顶并且最终只保留设置了 images 参数的页面。这正是列表页、首页聚合置顶优先 内容过滤场景的常用套路。与 intersect 的 AND 语义配合与unionOR互补的是intersectAND其实现见 tpl/collections/collections.go逻辑是双重循环找出同时存在于两个切片中的元素且结果顺序与第一个切片保持一致。官方文档 Intersect.md 中的示例与 Union 文档互为镜像——将其中第二行的union换成intersect就得到严格的全 AND 过滤。实践中建议按先用 union 放宽再用 intersect 收紧的顺序组合使用以获得可读性最强的模板表达式。与相关集合函数的对比union属于 Hugo collections 命名空间中集合运算一族同类函数各有分工函数语义说明union并集合并两切片并去重顺序为 l1 在前、l2 的新元素追加在后intersect交集取两切片公共元素结果顺序与 l1 一致uniq去重单切片内去除重复元素实现见 tpl/collections/collections.gocomplement补集返回不在后续切片中出现的元素实现见 tpl/collections/complement.gosymdiff对称差返回只出现在其中一个切片中的元素实现见 tpl/collections/symdiff.go如果你的需求是给现有切片去重用uniq更直接两个切片都出现过的元素用intersect除了某些页面之外的所有页面则可用complement。union最适合的定位是把两个来源不同的集合合并成一个不重复的大集合。类型支持与验证从单元测试到集成测试union的健壮性在测试层得到了充分验证单元测试TestUnion 覆盖了约 30 组用例包括nil 组合、同类型切片[]string、[]int、[]float64、[]T ∪ []any与[]any ∪ []T的混合类型、struct/指针类型如pagesPtr、pagesVals以及错误路径非切片入参、不可比较元素。测试确认了[]any{1, 2} ∪ []int{2, 3}返回[]any{1, 2, 3}这类跨类型归一化行为。集成测试TestUnionintegration 验证了union可以直接作用于 Hugo 的核心集合类型first 2 .Site.RegularPages | union .Site.RegularPages得到page.Pages类型且长度为 32 个去重后并入全部 3 个页面.Site.Taxonomies.tags.blue | union .Site.Taxonomies.tags.green得到page.WeightedPages类型且长度为 6。这证明union对页面切片Pages和标签加权切片WeightedPages同样适用而不仅限于普通标量切片。使用建议与注意事项综合文档与源码使用union时有以下几点值得牢记优先保证类型一致两个入参最好元素类型相同或至少一侧是[]any否则可能得到意外的空切片nil 是安全的可以放心对可能为空的集合做union函数会优雅降级返回非空侧或空切片不要对不可比较类型使用map、嵌套切片等元素类型会直接触发错误需先用uniq等策略或调整数据结构规避与管道组合使用$pages $pages | union ...的管道写法便于构建多步过滤管线可读性优于嵌套调用结果顺序有规律输出顺序为 l1 的元素顺序在前l2 中新增未重复元素按原顺序追加在后依赖顺序的场景如列表页排序可在union之后再使用sort等排序函数显式控制。围绕union的完整文档、实现与测试均可继续在仓库中深入阅读函数文档、核心实现、单元测试。【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表