解决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项目中使用init()
Apr 12 Golang
Go语言操作数据库及其常规操作的示例代码
Apr 21 Golang
基于Go Int转string几种方式性能测试
Apr 28 Golang
golang 在windows中设置环境变量的操作
Apr 29 Golang
golang 定时任务方面time.Sleep和time.Tick的优劣对比分析
May 05 Golang
go类型转换及与C的类型转换方式
May 05 Golang
golang 实现并发求和
May 08 Golang
聊聊golang中多个defer的执行顺序
May 08 Golang
golang实现浏览器导出excel文件功能
Mar 25 Golang
Golang 对es的操作实例
Apr 20 Golang
Golang实现可重入锁的示例代码
May 25 Golang
Go 内联优化让程序员爱不释手
Jun 21 Golang
Goland使用Go Modules创建/管理项目的操作
解决goland 导入项目后import里的包报红问题
Go 自定义package包设置与导入操作
goland 设置project gopath的操作
解决Goland 同一个package中函数互相调用的问题
浅谈golang package中init方法的多处定义及运行顺序问题
golang switch语句的灵活写法介绍
May 06 #Golang
You might like
用PHP调用Oracle存储过程的方法
2008/09/12 PHP
解析php中获取url与物理路径的总结
2013/06/21 PHP
PHP中SimpleXML函数用法分析
2014/11/26 PHP
php遍历树的常用方法汇总
2015/06/18 PHP
学习php设计模式 php实现命令模式(command)
2015/12/08 PHP
php新建文件的方法实例
2019/09/26 PHP
IE中jscript/javascript的条件编译
2006/09/07 Javascript
window.addeventjs事件驱动函数集合addEvent等
2008/02/19 Javascript
本地图片预览(支持IE6/IE7/IE8/Firefox3)经验总结
2013/03/25 Javascript
HTML页面弹出居中可拖拽的自定义窗口层
2014/05/07 Javascript
jQuery中:nth-child选择器用法实例
2014/12/31 Javascript
谈谈因Vue.js引发关于getter和setter的思考
2016/12/02 Javascript
一个有意思的鼠标点击文字特效jquery代码
2017/09/23 jQuery
vue注册组件的几种方式总结
2018/03/08 Javascript
Element Table的row-class-name无效与动态高亮显示选中行背景色
2018/11/30 Javascript
发布Angular应用至生产环境的方法
2018/12/10 Javascript
Python中类型关系和继承关系实例详解
2015/05/25 Python
Python实现给文件添加内容及得到文件信息的方法
2015/05/28 Python
Python使用os模块和fileinput模块来操作文件目录
2016/01/19 Python
python一行sql太长折成多行并且有多个参数的方法
2018/07/19 Python
Python基于plotly模块实现的画图操作示例
2019/01/23 Python
django的csrf实现过程详解
2019/07/26 Python
Python中remove漏删和索引越界问题的解决
2020/03/18 Python
HTML5 canvas绘制的玫瑰花效果
2014/05/29 HTML / CSS
SQL SERVER面试资料
2013/03/30 面试题
通用C#笔试题附答案
2016/11/26 面试题
Unix/Linux开发面试题
2016/08/16 面试题
业务经理的岗位职责
2013/11/16 职场文书
销售员求职个人的自我评价
2014/02/19 职场文书
股权转让意向书
2014/04/01 职场文书
小学竞选班长演讲稿
2014/09/09 职场文书
2014年销售工作总结范文
2014/12/01 职场文书
2016年“11.11”光棍节活动总结
2016/04/05 职场文书
《思路决定出路》读后感3篇
2019/12/11 职场文书
mysql批量新增和存储的方法实例
2021/04/07 MySQL
vue实现可拖拽的dialog弹框
2021/05/13 Vue.js