Go错误集锦 | 函数何时使用带参数名的返回值
01 具名返回值简介
在Go语言中定义方法或函数时,我们不仅可以给函数(或方法)的返回值指定返回类型,而且也可以指定返回参数的名字。如下函数就指定了返回值的名字:
func f(a int) (b int) {
b = a
return
}
在这种使用方式中,返回值参数(这里是b)首先会被初始化成返回类型的零值(这里int的零值是0)。其次,在return语句中可以不加任何参数,默认会将同名变量b的值返回。
02 何时使用带参数名的返回值
那么,在什么场景下会推荐使用带参数名的返回值呢?首先看一个接口示例:
type locator interface {
getCoordinates(address string) (float32, float32, error)
}
该接口中包含一个根据地址获取经纬度坐标的函数。在返回值中有两个float32类型的值,分别是经度和纬度。那么通过接口的签名你能知道返回值中哪个参数是经度,哪个参数是纬度吗?一般情况下,第一个参数会是纬度,第二个参数会是经度,但最终我们需要通过具体的实现函数来确认。
如果在方法的返回值中加上参数名称,那么通过函数的签名就可以很容易的确认每个返回值的含义了。如下:
type locator interface {
getCoordinates(address string) (lat, lng float32, error)
}
那么,在具体的实现该接口的方法中也需要在返回值中指定参数名吗?
func (l loc) getCoordinates(address string) (lat, lng float32, error) {
// ...
}
在这个示例中,因为有两个返回值类型是一样的,所以通过给返回值指定参数名可以提高代码的可读性,对于阅读代码的人来说就很容易知道哪个返回值是经度,哪个返回值是维度。
但在有的实现场景中,可以不用给返回值指定参数名,同样也不影响可读性。例如我们下面的代码,是将一个客户存储到数据库中的函数:
func StoreCustomer(customer Customer) (err error) {
// ...
}
那么,在这里我们给返回值指定了一个参数名就没什么意义。因为通过error类型我们就知道返回值一定是一个错误类型的。所以,在这种场景下,返回值指定了参数名也不会提高可读性,就尽量不要指定参数值名称。因为在指定了参数名的情况下,该参数会被初始化成对应类型的零值,如果不小心就可能会产生副作用。
03 返回值中命名参数的陷阱
在上面的示例中可以看到,在一些场景下,给返回值指定参数名称会提高可读性。但同时,返回值的参数值在函数一开始会被初始化成对应类型的零值。在业务逻辑中如果处理不当,就会造成错误。我们看下下面的这个例子:
func (l locator) getCoordinates(ctx context.Context, address string) (
lat, lng float32, err error) {
isValid := l.validateAddress(address)
if !isValid {
return 0, 0, errors.New("invalid address")
}
if ctx.Err() != nil {
return 0, 0, err
}
// Get and return coordinates
}
在该实现中,首先会通过validateAddress检查地址的合法性。然后会通过Context检查上层调用者是否因超时被取消。大家注意这里,如果ctx.Err()不等于nil,那么在返回err的时候,因为err没有被赋值,同时由于在返回值中指定了参数名被初始化成对应的零值nil,实际返回的err还是nil,不符合要返回具体错误的预期。解决方案应该如下:
if err := ctx.Err(); err != nil {
return 0, 0, err
}
04 总结
给函数返回值指定具体的参数名时,在某些场景下可以提高可读性,但同时因为返回值的参数在函数调用时会首先被初始化成对应类型的零值,在具体的逻辑处理中,如果不小心也会调入陷阱。
欢迎关注「Go学堂」,让我们再次走入学堂
相关文章
- Go 错误和异常
- 2022-09-10:以下go语言代码输出什么?A:编译错误;B:49.0;C:49。 package main import ( “fmt“ ) func m
- Go 进阶训练营 – 错误处理二:错误定义与处理
- 2022-10-31:以下go语言代码输出什么?A:map[];B:nil;C:Panic;D:编译错误。 package main import “fmt“
- Go 开发常用操作技巧--字符串
- Go中常见错误100例教程:第1章 Go易学难精
- Go常见错误集锦之切片使用不当会造成内存泄漏的那些场景
- 「Go工具箱」推荐一个变量调试神器:go-spew
- Go常见错误集锦之函数式选项模式
- GO的定时器Timer 和定时任务cron
- GO语言基础知识
- Go 模块 verifying xxx/go.mod: checksum mismatch 问题处理
- 【错误记录】Android Studio 中编写 Gradle 编译脚本时没有 Groovy 代码提示 ( Cannot find declaration to go to )
- go的数据类型-其他数据类型-pointer(一)
- Go-包管理-go mod(二)
- Go 语言中的 Slice 陷阱:如何避免常见错误
- Go语言bool类型(布尔类型)
- Go语言—小白入门-命令行库Cobra的使用详解编程语言
- Go语言使用类型断言来识别错误
- 深度探索Go语言与Redis结合(go-redis)
- 部署Linux下快速部署Go环境(go环境linux)
- 行操作Go Linux:基础命令行操作指南(golinux命令)
- SQL Server快速上手GO!(sqlserver go)
- Go语言与Linux:全新的开发环境体验(go语言linux)
- MySQL中使用Go语言的好处(mysql中go什么)
- Go语言查询Oracle数据库实战实例(go语言查询oracle)
- 数据库探索Go语言与Oracle数据库的结合(go语言中的oracle)
- ODBC数据驱动程序连接Oracle数据库Go语言之旅(go使用oracle)
- 程序Go语言调用Oracle数据库驱动程序指南(go oracle驱动)
- 使用go和python递归删除.dsstore文件的方法
- Go语言入门教程之基础语法快速入门