Go 函数中的参数为什么不支持默认值?

如果 Go 支持默认参数,下面这组 API 看起来完全可以合成一个函数:

go 复制代码
net.Dial("tcp", "db.internal:5432")
net.DialTimeout("tcp", "db.internal:5432", 3*time.Second)

例如假想一种并不存在的 Go 语法,把默认值写进声明:

go 复制代码
func Dial(network, address string, timeout time.Duration = 3*time.Second)

Dial("tcp", "db.internal:5432")

少一个函数名,也少写一个参数,确实方便。可一旦参数允许省略,往同一个函数里继续塞选项就变得很顺手。

今天只有 timeout,过一阵又加上重试次数、代理、保活时间:

text 复制代码
Dial(network, address,
     timeout = 3s,
     retries = 2,
     keepAlive = 30s,
     proxy = nil)

调用处仍然只有短短一行,函数承担的事情却越来越多。默认参数本身不难实现,Go 更警惕的是:一个函数借着默认值不断长出新行为,最后只能靠参数组合区分这些行为。

这正是 Go 当初不喜欢默认参数的地方。Rob Pike 在介绍 Go 设计时给过一句很直接的评价:默认参数太容易被拿来修补 API 设计问题。参数继续往函数后面加,原本应该拆开的行为就被藏进了一张越来越长的默认值表里。Go at Google

Go 的函数签名没有"可以省略的这一段"。规范里的普通参数必须逐一提供;只有最后一个 ...T 参数可以接收零个或多个同类型实参。Go 语言规范

于是 Go 标准库经常把语义差别写进 API 本身:

go 复制代码
net.Dial(network, address)
net.DialTimeout(network, address, timeout)

看到 DialTimeout,不用跳进源码,也知道这个调用主动规定了超时。这里还要分清:net.Dial 并没有暗藏一个固定的"三秒默认值",而是没有通过这个 API 显式设置超时;需要限定连接时间时,调用方改用 DialTimeout。两种语义直接写在了函数名上。

当选项确实很多时,Go 库通常把扩展点放到一个独立对象里。http.Client 就是这种写法:

go 复制代码
client := &http.Client{
	Timeout: 3 * time.Second,
}

resp, err := client.Get(url)

配置和执行分开以后,新增字段不需要改变 Get 的函数签名。另一种常见写法是函数式 Option。Go 官方关于模块兼容性的文章也专门讨论过这两种方案,同时提醒 Option 会增加名称和重复选项处理等复杂度;它不是默认参数换了件衣服就自动变好。Keeping Your Modules Compatible

变长参数也不能充当通用默认参数:

go 复制代码
func Dial(addr string, timeout ...time.Duration)

它只能表达"零个或多个同类型值"。函数内部还得决定传两个超时时怎么办,调用处也看不出省略参数代表永不超时还是使用某个默认值。参数一多,最后很容易滑到 ...any,类型检查也跟着变弱。

所以我看一个 Go API 要不要再塞一个可选参数,通常先看它是不是一种新的行为。若是,就给它一个能说清差别的名字,或者把它收进配置对象。Dial 和 DialTimeout 多占了一个名字,但调用代码自己带着说明书。

相关推荐
小羊没烦恼!4 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里4 天前
java中的继承和多态的区别
java
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕4 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码4 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖4 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时4 天前
01-06-A-JVM排查实战详解
java·jvm
伞伞悦读4 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
vipxieliang4 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
C语言小火车4 天前
C/C++ 为什么需要编译器?
开发语言·c++