解决golang 关于全局变量的坑


Posted in Golang onMay 06, 2021

学习golang不久,在定义全局变量的时候遇见了坑。写个小例子,增强记忆。

错误版本

var p int
func main() {
 p, err := test(4)
 if err != nil {
  log.Fatal(err)
 }
}
func test(i int) (int, error) {
 return i + 1, nil
}

编译一直不通过,p declared and not used。后来查了查资料,看见这种其实是在main里边又重新定义了p,所以一直提示p定义了但是没有使用。修改如下:

正确版本

var p int
func main() {
 var err error
 p, err = test(4)
 if err != nil {
  log.Fatal(err)
 }
}
func test(i int) (int, error) {
 return i + 1, nil
}

补充:golang变量作用域问题-避免使用全局变量

最近遇到了一个变量作用域的问题,一个比较低级的问题,可能作为一个熟手不应该犯这样的低级错误,但是golang的语法特点可能让你稍微不注意就踩坑,嘿嘿。

变量作用域

全局变量的作用域是整个包,局部变量的作用域是该变量所在的花括号内,这是一个很基础的问题。

我们通常会使用golang的一个语法糖:=来给变量赋值,这种方式可以节省掉我们定义变量的代码,让代码变的更加简洁,但是如果你定义了一个全局变量,又不小心用:=来给它赋值,就会出现一些问题。

问题

看下面的代码,定义了一个全局变量t,我想在init()中给他赋值为2,然后在main中使用它。

var t int
func init() {
    t, err := strconv.Atoi("2")
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println("init:", t)
}
func main() {
    fmt.Println("main:", t)
}

输出:

init: 2

main: 0

执行之后,在init和main中打印出了不一样的数字,为什么会不一样呢,可能你仔细一看就知道原因了。很简单,init中的t是用:=生成的,所以t是局部变量,在init函数中覆盖了全局变量t。全局变量t并没有被赋值,它还是原来的0值。

我本想在init中给全局变量t赋值的,却不小心用:=创建了一个局部变量导致全局变量t没有赋值成功,犯了一个低级错误。

解决

知道原因之后就容易解决了,我不使用:=就可以了。代码如下:

var t int
func init() {
    var err error
    t, err = strconv.Atoi("2")
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println("init:", t)
}
func main() {
    fmt.Println("main:", t)
}

输出:

init: 2

main: 2

没有使用:=之后,init中的t就是全局变量t,给全局变量t赋值为2,main中自然输出的就是2,实现了我最初的目的。

思考

这个问题很简单很低级,但是可能一个golang熟手,在代码远比demo要复杂的多的实际项目中,不经意间就可能会犯下这样的错误。

这个问题很难保证说下次一定不会出现的,除非你彻底不用全局变量或者彻底不用:=这样的语法糖。

我的建议是这样:

尽量少的使用全局变量。

尽量少的使用:=语法糖。

使用:=的时候要确保左值没有被定义过。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
基于go interface{}==nil 的几种坑及原理分析
Apr 24 Golang
Golang 正则匹配效率详解
Apr 25 Golang
go设置多个GOPATH的方式
May 05 Golang
Goland使用Go Modules创建/管理项目的操作
May 06 Golang
关于golang高并发的实现与注意事项说明
May 08 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
手把手教你导入Go语言第三方库
Aug 04 Golang
Golang表示枚举类型的详细讲解
Sep 04 Golang
详解Golang如何优雅的终止一个服务
Mar 21 Golang
Go归并排序算法的实现方法
Apr 06 Golang
Go并发4种方法简明讲解
Apr 06 Golang
Golang并发工具Singleflight
May 06 Golang
Goland使用Go Modules创建/管理项目的操作
解决goland 导入项目后import里的包报红问题
Go 自定义package包设置与导入操作
goland 设置project gopath的操作
解决Goland 同一个package中函数互相调用的问题
浅谈golang package中init方法的多处定义及运行顺序问题
golang switch语句的灵活写法介绍
May 06 #Golang
You might like
ThinkPHP行为扩展Behavior应用实例详解
2014/07/22 PHP
Symfony的安装和配置方法
2016/03/17 PHP
分享几种好用的PHP自定义加密函数(可逆/不可逆)
2020/09/15 PHP
jQuery 使用手册(六)
2009/09/23 Javascript
javascript小数计算出现近似值的解决办法
2010/02/06 Javascript
JQuery+DIV自定义滚动条样式的具体实现
2013/06/25 Javascript
在js文件中写el表达式取不到值的原因及解决方法
2013/12/23 Javascript
jQuery基于BootStrap样式实现无限极地区联动
2016/08/26 Javascript
JavaScript数据类型学习笔记分享
2016/09/01 Javascript
原生JS和jQuery操作DOM对比总结
2017/01/19 Javascript
jQuery实现文档树效果
2017/02/20 Javascript
利用Ionic2 + angular4实现一个地区选择组件
2017/07/27 Javascript
js防刷新的倒计时代码 js倒计时代码
2017/09/06 Javascript
JavaScript判断输入是否为数字类型的方法总结
2017/09/28 Javascript
简单的Vue SSR的示例代码
2018/01/12 Javascript
Vue父组件调用子组件事件方法
2018/02/23 Javascript
Vue 样式绑定的实现方法
2019/01/15 Javascript
JointJS JavaScript流程图绘制框架解析
2019/08/15 Javascript
基于better-scroll 实现歌词联动功能的代码
2020/05/07 Javascript
Nodejs在局域网配置https访问的实现方法
2020/10/17 NodeJs
Python计算两个日期相差天数的方法示例
2017/05/23 Python
浅谈Django REST Framework限速
2017/12/12 Python
python3如何将docx转换成pdf文件
2018/03/23 Python
numpy.transpose对三维数组的转置方法
2018/04/17 Python
Python 单元测试(unittest)的使用小结
2018/11/14 Python
Python基础之文件读取的讲解
2019/02/16 Python
Pytorch在NLP中的简单应用详解
2020/01/08 Python
python爬取豆瓣电影排行榜(requests)的示例代码
2021/02/18 Python
Waterford加拿大官方网站:世界著名的水晶杯品牌
2016/11/01 全球购物
Expedia韩国官网:亚洲发展最快的在线旅游门户网站
2018/02/26 全球购物
Moda Italia荷兰:意大利男士服装
2019/08/31 全球购物
英国豪华家具和家居用品购物网站:Teddy Beau
2020/10/12 全球购物
中学生班主任评语
2014/01/30 职场文书
小区的门卫岗位职责
2014/10/01 职场文书
2014年扫黄打非工作总结
2014/12/03 职场文书
巾帼文明岗事迹材料
2014/12/24 职场文书