当前位置:首页 > 文章列表 > Golang > Go教程 > Go slices.Compact 怎样判断输入是否满足边界

Go slices.Compact 怎样判断输入是否满足边界

来源:17golang原创 2026-11-03 17:57:16 0浏览 收藏

如果你想判断一个输入是否适合交给 slices.Compact,先看“重复是否相邻”,再看结果长度是否变化。这个函数只会把连续相等的一段压成一个元素,不会排序,也不会把分散在切片不同位置的相同值自动合并。

官方文档:https://pkg.go.dev/slices#Compact

从 Go 1.21 开始,标准库提供了 slices 包。使用 Compact 前,可以把边界分成五类:nil 或空切片、只有一个元素、已经没有相邻重复、存在相邻重复、重复值不相邻。前四类的判断方式不同,最后一类则说明数据还不满足“连续压缩”的业务前提。

先确认输入是不是连续重复

Compact 的比较范围是相邻元素。下面的两组输入看起来都有重复值,但只有第一组会被压缩:

// 这段示例用相邻比较区分 Compact 能处理的重复和分散重复。
package main

import (
    "fmt"
    "slices"
)

func main() {
    adjacent := []string{"go", "go", "rust", "rust", "go"}
    separated := []string{"go", "rust", "go", "rust"}

    adjacent = slices.Compact(adjacent)
    separated = slices.Compact(separated)

    fmt.Println(adjacent)  // 结果只保留每段连续值的第一个元素。
    fmt.Println(separated) // 分散重复没有相邻关系,仍会保留。
}

因此,标题里的“满足边界”不是判断切片里有没有重复值,而是判断重复是否以连续分组的形式出现。如果业务要求全局去重,需要先明确顺序、哈希表或排序策略,不能直接把 Compact 当成全局去重函数。

输入切片中相邻重复与非相邻重复的范围说明图
图1:slices.Compact 只处理相邻连续重复项的范围说明图,不是运行截图。

用相邻比较预判输入会不会变化

如果调用方需要在压缩前记录“输入是否已经满足边界”,可以只检查每一对相邻元素。泛型约束与 Compact 一样使用可比较元素:

// hasAdjacentEqual 只回答一个问题:切片里是否存在相邻相等元素。
// 它不排序、不修改输入,也不负责判断所有重复值。
func hasAdjacentEqual[S ~[]E, E comparable](s S) bool {
    for i := 1; i 

这个判断天然覆盖几个边界:

  • nil 和 []T{} 的长度都不超过 1,不存在相邻元素。
  • 单元素切片没有可比较的相邻位置,调用后长度不会变化。
  • 每一对相邻值都不相等时,输入已经满足“没有连续重复”的边界。
  • 只要找到一对相邻相等的值,结果就可能变短,但变短多少要由连续段长度决定。

要注意“可能变短”而不是“必然得到某个固定长度”。例如连续段可以出现在开头、中间或结尾,多个连续段也会同时被压缩。

调用后以返回长度作为结果边界

Compact 会返回处理后的切片,所以应当接住返回值。原来的切片变量不会因为函数在内部修改了底层数组,就自动拥有新的长度:

// 以返回值覆盖原变量,后续遍历才会使用压缩后的长度。
func compactNames(names []string) []string {
    before := len(names)
    names = slices.Compact(names)
    after := len(names)

    // before 和 after 用来记录业务上是否发生了压缩。
    if after  %d\n", before, after)
    }
    return names
}

如果只是想知道输入是否会变化,调用前的 hasAdjacentEqual 更直接;如果最终一定要得到压缩后的数据,则以 slices.Compact 返回值的长度为准。两者不要混成一个“检查函数”,否则容易把预判结果误当成处理结果。

别忽略 nil、空切片和元素类型

文档明确说明,Compact 会保留输入的 nil 性质。也就是说,nil 切片经过处理后仍然是 nil;非 nil 的空切片也不会凭空变成 nil。这一点在接口序列化、缓存命中和“未提供”与“提供但为空”的业务语义中很重要。

// 这个例子只展示 nil 性质的判断,不把 nil 和空切片混为一谈。
func sameNilness() {
    var nilItems []int
    emptyItems := make([]int, 0)

    nilItems = slices.Compact(nilItems)
    emptyItems = slices.Compact(emptyItems)

    fmt.Println(nilItems == nil)   // nil 输入仍保持 nil。
    fmt.Println(emptyItems == nil) // 非 nil 空切片仍不是 nil。
}

此外,Compact 要求元素类型满足 comparable,因为它需要用相等运算判断相邻值。包含切片、映射或函数字段的复杂对象不能直接作为元素类型调用;这时应先定义业务等价关系,再考虑 slices.CompactFunc 是否适合。

理解底层数组复用带来的尾部边界

压缩通常会复用原切片的底层数组。返回值的 len 变短,cap 可能仍然保留;新长度之后的元素会被清零。调用方应该只通过返回切片访问有效数据,不要把原容量当成结果长度。

Compact 返回长度与底层数组复用和尾部清零的关系说明图
图2:Compact 返回切片与底层数组复用关系的说明图,不是运行截图。
// 只把 returned 当作有效范围,避免误读底层数组尾部。
func compactTags(tags []string) []string {
    tags = slices.Compact(tags)
    // tags[:len(tags)] 才是业务有效数据;不要按 cap(tags) 遍历。
    return tags
}

如果尾部元素曾经持有指针或较大的对象引用,清零可以帮助释放这些不再属于结果的引用。但这不代表压缩后就一定分配了新数组,也不代表原切片的所有别名都会同步缩短;多个切片视图仍可能指向同一个底层数组。

一张表判断是否满足使用边界

输入情况是否属于 Compact 的处理范围处理建议
nil 或空切片可以调用,结果长度不变保留 nil 与空值语义
只有一个元素可以调用,结果长度不变无需为压缩额外分支
存在相邻相等元素满足,结果可能变短接住返回值并使用新长度
重复值不相邻不满足全局去重目标先重新组织数据或选择其他算法
元素不可比较不能直接调用 Compact定义等价函数后评估 CompactFunc

实际工程里,可以把判断顺序固定为:先确认目标是“压缩连续重复”,再检查元素是否可比较,最后接住返回值并只按新长度读取。这样既不会误删分散重复,也不会因为原切片容量还在就把尾部当成有效记录。

常见问题

slices.Compact 会自动排序吗?

不会。它只比较相邻元素,输入顺序不会被重新排列。

为什么调用后原切片看起来还有旧元素?

原变量的长度不会自动更新,或者你观察的是同一底层数组的其他切片视图。业务代码应使用函数返回值,并按新长度访问。

不相邻的重复值怎样删除?

先确定是否需要保序,再选择哈希集合、排序后压缩或其他专门算法;不要把 Compact 的相邻语义误当成全局去重。

什么时候考虑 CompactFunc?

当元素本身不可直接用 == 表达业务等价关系时,可以先设计比较函数,再确认连续相等的语义仍然符合需求。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go slices.Compact 怎样去除连续重复元素并保留原切片顺序Go slices.Compact 怎样去除连续重复元素并保留原切片顺序
上一篇
Go slices.Compact 怎样去除连续重复元素并保留原切片顺序
Go slices.Compact 怎样复用已有缓冲空间
下一篇
Go slices.Compact 怎样复用已有缓冲空间
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之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模型性能。
    866次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    868次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    947次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    924次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    757次使用