- 6.2.2. 首选可变参数函数而非
[]T
参数
6.2.2. 首选可变参数函数而非 []T
参数
编写一个带有切片参数的函数或方法是很常见的。
func ShutdownVMs(ids []string) error
这只是我编的一个例子,但它与我所写的很多代码相同。 这里的问题是他们假设他们会被调用于多个条目。 但是很多时候这些类型的函数只用一个参数调用,为了满足函数参数的要求,它必须打包到一个切片内。
另外,因为 ids
参数是切片,所以你可以将一个空切片或 nil
传递给该函数,编译也没什么错误。 但是这会增加额外的测试负载,因为你应该涵盖这些情况在测试中。
举一个这类 API 的例子,最近我重构了一条逻辑,要求我设置一些额外的字段,如果一组参数中至少有一个非零。 逻辑看起来像这样:
if svc.MaxConnections > 0 || svc.MaxPendingRequests > 0 || svc.MaxRequests > 0 || svc.MaxRetries > 0 {
// apply the non zero parameters
}
由于 if
语句变得很长,我想将签出的逻辑拉入其自己的函数中。 这就是我提出的:
// anyPostive indicates if any value is greater than zero.
func anyPositive(values ...int) bool {
for _, v := range values {
if v > 0 {
return true
}
}
return false
}
这就能够向读者明确内部块的执行条件:
if anyPositive(svc.MaxConnections, svc.MaxPendingRequests, svc.MaxRequests, svc.MaxRetries) {
// apply the non zero parameters
}
但是 anyPositive
还存在一个问题,有人可能会这样调用它:
if anyPositive() { ... }
在这种情况下,anyPositive
将返回 false
,因为它不会执行迭代而是立即返回 false
。对比起如果 anyPositive
在没有传递参数时返回 true
, 这还不算世界上最糟糕的事情。
然而,如果我们可以更改 anyPositive
的签名以强制调用者应该传递至少一个参数,那会更好。我们可以通过组合正常和可变参数来做到这一点,如下所示:
// anyPostive indicates if any value is greater than zero.
func anyPositive(first int, rest ...int) bool {
if first > 0 {
return true
}
for _, v := range rest {
if v > 0 {
return true
}
}
return false
}
现在不能使用少于一个参数来调用 anyPositive
。