Go语言中常见100问题-#1 Unintended variable shadowing
小心变量遮蔽
变量的作用域是指一个变量可以被引用的地方/范围。换句话说,就是应用程序的一个区域,在该区域内变量是有效的,超出该区域便无效。在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
上面的程序首先定义了一个客户端变量client, 然后在两个内部代码块中使用短变量声明运算符(:=)赋值,虽然赋值给的变量也是client,但是它与外面的client不是同一个,因此,执行上述程序外部的client始终为nil.
「NOTE: 上面的代码可以编译通过,因为内部赋值的client变量在log.Println中使用到了,否则的话,将出现编译错误,提示client(内部的)声明但未使用。」
如何修复上面代码中存在的问题呢?有两种不同的方法。方法一是在内部代码块中使用一个临时变量保存client,此临时变量名不要使用client,然后再将临时变量值赋值给client, 实现代码如下。这里先将结果保存在临时变量c中,c的作用域在if块中,最后再将c赋值给客户端变量client.
var client *http.Client
if tracing {
c, err := createClientWithTracing()
if err != nil {
return err
}
client = c
} else {
// Same logic
}
方法二是使用赋值运算符(=)将创建结果直接分配给客户端变量client,但是需要创建一个错误变量,因为赋值运算符(=)对已声明的变量才能使用。然后直接将创建结果分配给client,实现如下。
var client *http.Client
var err error
if tracing {
client, err = createClientWithTracing()
if err != nil {
return err
}
} else {
// Same logic
}
上述两种方法都是正确的,主要区别在于方法二种只执行了一个赋值操作,阅读起来可能更容易。此外,使用方法二,可以在if/else语句之后统一对错误进行处理。
if tracing {
client, err = createClientWithTracing()
} else {
client, err = createDefaultClient()
}
if err != nil {
// Common error handling
}
总结,在内部代码块中重新声明变量时,会产生变量遮蔽/隐藏,通过前面的例子可以看到这种做法很容易出错。所以在编码中,注重代码品味,尽量不要犯变量遮蔽/隐藏问题。虽然有时重用现有变量会非常方便,例如在用err表示错误时。但是,总体来说,我们应该谨慎小心,否则很容易出现问题,像本文举的例子,接收到值的变量不是我们预期的变量。
相关文章
- 2022-09-26:以下go语言代码输出什么?A:{“Time“: “2020-12-20T00:00:00Z“, “N“: 5 };B:“2020-12-2
- JetBrains GoLand 2022 Mac中文激活版(GO语言编程软件)
- 【R语言】解决GO富集分析绘图,标签重叠问题
- 2022-10-26:以下go语言代码输出什么?A:1 3 2;B:1 2 3;C:3 1 2;D:3 2 1。 package main import “fm
- 「Go工具箱」go语言csrf库的使用方式和实现原理
- 2022-08-11:以下go语言代码输出什么?A:panic;B:编译错误;C:json marshal 报错;D:null;
- 2022-09-06:以下go语言代码输出什么?A:Hi All;B:Hi go All;C:Hi;D:go All。packa
- Go语言中常见100问题-#5 Interface pollution
- Go语言中常见100问题-#8 any says nothing
- Go语言中常见100问题-#12 Project misorganization
- Go语言中常见100问题-#13 Creating utility packages
- Go语言中常见100问题-#14 Ignoring package name collisions
- Go语言中常见100问题-#18 Neglecting integer overflows
- Go语言中常见100问题-#20 Not understanding slice length and capacity
- 「Go工具箱」推荐一个变量调试神器:go-spew
- 2022-11-08:以下go语言代码输出什么?A:2;B:编译错误;C:运行 panic。package mainimport
- GO语言开篇-Go语言急速入门(基础知识点)| 青训营笔记
- Go语言实现Web服务器
- Go语言go mod包依赖管理工具使用详解
- go pprof命令(Go语言性能分析命令)完全攻略
- go语言之数组详解编程语言
- go语言之指针详解编程语言
- 安装Go语言开发包
- Go语言找出重复行
- 编程新精英:Go语言 Redis开发(go语言redis开发)
- 轻松搞定Go语言连接MySQL(go连接mysql)
- 语言结合SQL Server,Go谱写新篇章(sqlserver的go)
- Go语言操作Oracle轻松实现数据库编程(go语言访问oracle)
- 前行不止Go语言监听Oracle日志(go监听oracle日志)
- 数据库Go语言实现监控Oracle数据库(go监听oracle)
- ODBC数据驱动程序连接Oracle数据库Go语言之旅(go使用oracle)
- GO语言延迟函数defer用法分析