阳了快一个星期了,没有更新文章。也在思考发些什么内容比较实用。之前发的一些文章都是比较基础的适合普通的Go开发人员交流学习。之前看到国外有人在整理Go的常见错误,这个也是每个编程人都希望掌握的,毕竟谁都不想犯错。
现在网上也可以阅读原版内容了,这里我也把相关的一些内容翻译下,供大家参考。
今天要介绍的第一个易犯错误就是,变量作用域导致的。
变量的作用域是指变量可以被引用的范围。换句话说,是应用程序中变量名绑定有效的部分。在Go语言中,在代码块中声明的变量名可以在内部代码块中重新声明。这个原理被称为变量遮蔽,容易犯常见错误。
下面的示例显示了由于变量遮蔽而产生的意外副作用。它以两种不同的方式创建HTTP客户端,这取决于tracing的值:
var client *http.Client ❶
if tracing {
client, err := createClientWithTracing() ❷
if err != nil {
return err
}
log.Println(client)
} else {
client, err := createDefaultClient() ❸
if err != nil {
return err
}
log.Println(client)
}
// Use client
1、申明一个client变量
2、如果tracing是true创建HTTP客户端。在这里第一步定义的client变量被遮蔽。
3、创建一个默认http客户端。这里也会发生变量的遮蔽。
在这个例子中,我们首先申明client变量。然后在内部代码块if...else..中使用短变量申明操作符(:=)将函数返回值赋给内部变量client,而不是外部client变量。因此,外部变量client还是初始值nil。
注意:这段代码能编译通过,是因为内部client变量在log.Println中使用了。否则,编译会报错例如client declared and not used.
我们该如何确保最初的client变量被正确赋值呢?
第一种方法:在内部代码块中使用临时变量,如下所示:
var client *http.Client
if tracing {
c, err := createClientWithTracing() ❶
if err != nil {
return err
}
client = c ❷
} else {
// Same logic
}
1、创建临时变量c。
2、将临时变量值赋给client。
这里将函数调用结果赋值给脸是变量c,它的作用域只在if...else...代码块范围内。然后将值赋给client。同时对else部分做相同处理。
第二种方法:在内层代码块里面使用赋值操作符(=),将函数返回值直接赋给client变量。但是,这里需要定义error变量,因为赋值操作符仅作用于已经定义的变量。例如:
var client *http.Client
var err error ❶
if tracing {
client, err = createClientWithTracing() ❷
if err != nil {
return err
}
} else {
// Same logic
}
1、申明err变量。
2、使用赋值操作符将返回的*http.Client值直接赋给client变量。
这里取代传值给临时变量,而是直接将结果传给client。
以上两种方式都有效。主要区别在第二种方法只需要一次赋值,使代码便于阅读。同时,使用第二种方式,我们可以在if/else语句之外实现错误处理。
if tracing {
client, err = createClientWithTracing()
} else {
client, err = createDefaultClient()
}
if err != nil {
// Common error handling
}
当在内部代码块中重新声明变量名时,就会发生变量遮蔽,但我们看到这种做法容易出错。禁止变量遮蔽的规则取决于个人喜好。例如,有时重用现有的变量名(如err用于错误)会很方便。然而,一般来说,我们应该保持谨慎,因为我们现在知道可能会面临这样的场景:代码可编译完成,但接收值的变量不是预期的值。
网友评论