解决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
golang 实现对Map进行键值自定义排序
Apr 28 Golang
Go使用协程交替打印字符
Apr 29 Golang
解决Go gorm踩过的坑
Apr 30 Golang
解决golang post文件时Content-Type出现的问题
May 02 Golang
golang 实现并发求和
May 08 Golang
victoriaMetrics库布隆过滤器初始化及使用详解
Apr 05 Golang
Go语言安装并操作redis的go-redis库
Apr 14 Golang
golang用type-switch判断interface的实际存储类型
Apr 14 Golang
GO中sync包自由控制并发示例详解
Aug 05 Golang
Go gorilla securecookie库的安装使用详解
Aug 14 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 第二节 数据类型之转换
2012/04/28 PHP
php中判断文件存在是用file_exists还是is_file的整理
2012/09/12 PHP
php将12小时制转换成24小时制的方法
2015/03/31 PHP
深入浅析PHP7.0新特征(五大新特征)
2015/10/29 PHP
php 无限级分类 获取顶级分类ID
2016/03/13 PHP
php处理抢购类功能的高并发请求
2018/02/08 PHP
js菜单点击显示或隐藏效果的简单实例
2014/01/13 Javascript
浅谈JavaScript中Date(日期对象),Math对象
2015/02/05 Javascript
TinyMCE提交AjaxForm获取不到数据的解决方法
2015/03/05 Javascript
在JavaScript中处理数组之reverse()方法的使用
2015/06/09 Javascript
JS实现Select的option上下移动的方法
2016/03/01 Javascript
举例说明JavaScript中的实例对象与原型对象
2016/03/11 Javascript
基于Bootstrap+jQuery.validate实现表单验证
2016/05/30 Javascript
iOS和Android用同一个二维码实现跳转下载链接的方法
2016/09/28 Javascript
JS监控关闭浏览器操作的实例详解
2017/09/12 Javascript
js中对象与对象创建方法的各种方法
2019/02/27 Javascript
JQuery特殊效果和链式调用操作示例
2019/05/13 jQuery
nestjs中异常过滤器Exceptionfilter的具体使用
2021/02/07 Javascript
Python-基础-入门 简介
2014/08/09 Python
python批量生成本地ip地址的方法
2015/03/23 Python
Python中内置的日志模块logging用法详解
2016/07/12 Python
Python 爬虫学习笔记之多线程爬虫
2016/09/21 Python
Python中.join()和os.path.join()两个函数的用法详解
2018/06/11 Python
Win8.1下安装Python3.6提示0x80240017错误的解决方法
2018/07/31 Python
django实现用户注册实例讲解
2019/10/30 Python
Python序列类型的打包和解包实例
2019/12/21 Python
Bjorn Borg官方网上商店:国际运动时尚品牌
2016/08/27 全球购物
Nisbets法国:英国最大的厨房和餐饮设备供应商
2019/03/18 全球购物
亚洲颇具影响力的男性在线购物零售商:His
2019/11/24 全球购物
药学专业大学生个人的自我评价
2013/11/04 职场文书
小饰品店的创业计划书范文
2013/12/28 职场文书
建筑项目策划书
2014/01/13 职场文书
庆七一活动总结
2014/08/27 职场文书
民事撤诉申请书范本
2015/05/18 职场文书
预备党员考察意见范文
2015/06/01 职场文书
Java面试题冲刺第十九天--数据库(4)
2021/08/07 Java/Android