当前位置:首页 > 文章列表 > Golang > Go教程 > Go cmp.Or 怎么从多个候选值中选择第一个非零值

Go cmp.Or 怎么从多个候选值中选择第一个非零值

来源:17golang原创 2026-10-04 04:27:39 0浏览 收藏

直接说结论:Go 的 cmp.Or 会从左到右检查传入的候选值,返回第一个不等于该类型零值的值;如果所有候选都是零值,就返回该类型的零值。它特别适合表达“命令行参数优先,其次环境变量,最后内置默认值”这类简单的配置回退。

官方文档:https://pkg.go.dev/cmp

这个函数从 Go 1.22 开始提供,签名中的类型约束是 comparable,因此所有候选必须能使用等号比较,并且属于同一种可推断类型。

cmp.Or 从多个同类型候选值中选择第一个非零值的静态结构图
图1:静态说明图,零值候选被依次跳过,第一个非零值成为返回结果。

最小写法:把候选值按优先级排好

最常见的使用方式是把优先级最高的候选放在最前面,把兜底值放在最后。下面的例子中,命令行没有设置地址,环境变量提供了地址,因此最终选择环境变量的值。

package main

import (
    "cmp"
    "fmt"
)

func main() {
    // 候选值按优先级从高到低排列
    flagAddr := ""
    envAddr := "10.0.0.8:8080"
    defaultAddr := "127.0.0.1:8080"

    addr := cmp.Or(flagAddr, envAddr, defaultAddr)
    fmt.Println(addr)
}
10.0.0.8:8080

这里没有特殊的“默认值标记”。对字符串来说,空字符串就是零值,所以第一个候选被跳过;第二个候选非空,函数立即把它作为结果。

问题通常出在没有先想清楚“零值”

cmp.Or 判断的不是“这个值是否合理”,而是“这个值是否等于其类型的零值”。不同类型的零值不同:

类型示例零值使用时的含义
string空字符串常用于“未提供文本配置”
int、float640只有业务上把 0 视为缺省时才适合
boolfalsefalse 会被当成未选择,容易丢失显式关闭意图
指针nil可在多个可选对象之间取第一个非 nil 值
可比较结构体各字段均为零值整个结构体与其零值比较

因此,端口号用 0 表示“自动分配”时,不能再把 0 同时当作“未配置”。如果业务语义需要区分这两种状态,应增加显式的是否设置标志,或者使用指针、可选值结构。

动手验证:全部为零值时会发生什么

全部候选都是零值并不会报错。函数会返回同类型的零值;不传任何候选时也遵循这一规则,只要类型能够从上下文或显式类型实参中确定。

package main

import (
    "cmp"
    "fmt"
)

func main() {
    // 三个候选都是字符串零值,因此结果仍为空字符串
    text := cmp.Or("", "", "")

    // 没有实参时显式指定类型,结果是 int 的零值 0
    number := cmp.Or[int]()

    fmt.Printf("text=%q number=%d\n", text, number)
}
text="" number=0

这也是为什么把兜底值放在最后很重要:只要兜底值本身非零,正常配置路径就总能得到一个明确结果。

类型限制:slice、map 和 function 不能直接传入

cmp.Or 的类型参数要求 comparable。字符串、数字、布尔值、指针、通道、接口,以及字段都可比较的数组和结构体可以使用;slice、map 和 function 不能作为普通值直接比较,因此不能直接作为候选传入。

cmp.Or 对 comparable 类型、零值语义和不可直接使用类型的静态关系图
图2:静态关系图,能否调用取决于 comparable 约束,是否适合还取决于零值是否等于业务上的“未设置”。

如果要从多个切片中选择第一个非空切片,仍然需要显式判断长度。这样写也更准确,因为 nil 切片和长度为 0 的非 nil 切片在业务上是否等价,需要由调用方决定。

package main

import "fmt"

func firstNonEmpty[T any](candidates ...[]T) []T {
    // slice 不满足 comparable,因此按长度显式判断
    for _, candidate := range candidates {
        if len(candidate) > 0 {
            return candidate
        }
    }
    return nil
}

func main() {
    // 返回第一个长度大于 0 的切片
    result := firstNonEmpty([]int{}, []int{3, 5}, []int{8})
    fmt.Println(result)
}
[3 5]

两个容易忽略的边界

false 或 0 可能是有效输入

如果用户明确填写 false 表示关闭功能,使用 cmp.Or 会继续选择后面的 true,从而改变用户意图。同理,0 如果代表“不限速”“自动端口”或某个有效枚举,也不应被无条件跳过。此时应该保存“是否设置”的独立状态,而不是只看值本身。

它不是惰性求值工具

调用函数前,Go 会先求出每个实参的值。因此即使第一个候选已经非零,写在后面的函数调用也已经执行。若候选计算昂贵、可能失败或带副作用,应继续使用 if 判断,让后续计算只在确实需要时发生。

func loadValue(primary string) string {
    if primary != "" {
        // 已有主值时直接返回,避免继续执行昂贵查询
        return primary
    }
    return queryRemoteFallback()
}

速查:什么时候值得用 cmp.Or

  • 候选值类型相同,并且满足 comparable 约束。
  • 该类型的零值在业务上确实表示“未提供”。
  • 候选值已经准备好,不依赖惰性计算或错误处理。
  • 优先级可以清楚地用从左到右的参数顺序表达。
  • 最后最好提供一个非零兜底值,避免结果仍是零值。

总结:把 cmp.Or 理解成“按顺序选择第一个非零值”就够了。它能明显压缩简单的默认值选择代码,但不会判断业务有效性,也不会替你区分 false、0 与“未设置”。先确认零值语义,再决定是否用它。

相关问题

cmp.Or 可以混用 string 和自定义字符串类型吗?

一次调用中的候选必须能推断成同一个类型。若自定义类型与 string 不能直接统一,应先显式转换成目标类型。

cmp.Or 会返回候选值的副本吗?

它按 Go 的普通值传递规则返回该值。对指针、通道或接口等引用语义相关的值,返回结果仍然指向相应对象,并不会自动深拷贝。

可以用 cmp.Or 代替所有 if 默认值判断吗?

不可以。需要区分零值与未设置、需要惰性计算、需要处理错误,或者候选类型不可比较时,显式 if 通常更清楚。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
qooapp是游戏平台还是资讯社区?游戏商店、媒体与玩家功能边界说明qooapp是游戏平台还是资讯社区?游戏商店、媒体与玩家功能边界说明
上一篇
qooapp是游戏平台还是资讯社区?游戏商店、媒体与玩家功能边界说明
繁花动漫免费吗?公开页面宣传、广告与内容来源边界说明
下一篇
繁花动漫免费吗?公开页面宣传、广告与内容来源边界说明
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之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模型性能。
    323次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    378次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    375次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    338次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    164次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码