解决golang 关于全局变量的坑

学习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要复杂的多的实际项目中,不经意间就可能会犯下这样的错误。

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

我的建议是这样:

尽量少的使用全局变量。

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

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

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

(0)

相关推荐

  • 详解Go语言变量作用域

    作用域为已声明标识符所表示的常量.类型.变量.函数或包在源代码中的作用范围. Go 语言中变量可以在三个地方声明: 函数内定义的变量称为局部变量 函数外定义的变量称为全局变量 函数定义中的变量称为形式参数 接下来让我们具体了解局部变量.全局变量和形式参数. 局部变量 在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量. 以下实例中 main() 函数使用了局部变量 a, b, c: package main   import "fmt"   fu

  • go语言的初始化顺序,包,变量,init详解

    依次见例子代码: p1.go package p1 import "fmt" //1.1 var x float32 = 1.2 //1.2 func init() { //1.3 fmt.Printf("p1 package, x:%f\n", x) //1.4 } func Donothing() { fmt.Println("do nothing.\n") } a.go: package main import "fmt"

  • 关于Golang变量初始化/类型推断/短声明的问题

    视频: https://www.bilibili.com/video/BV1Zh411k7iB/ 声明变量同时初始化 上节我们了解了三种变量声明的语法,并且知道未初始化的变量初始值都是其类型的零值 其实只需要在声明时赋予初始值,即可进行初始化 下面针对三种变量声明语法进行初始化: [1] var name type [2] var name1, name2 type [3] var ( name1 type1 name2 type2 ) 类型推断 如果变量声明时附带初始值,Go会自动推断出初始值

  • go语言 全局变量和局部变量实例

    一.局部变量 1 定义在{}里面的变量时局部变量,只能在{}里面有效 2 执行到定义的那句话,开始分配内存空间,离开作用域自动进行释放 3 作用域,就是变量作用的范围 package main import "fmt" func test() { i := 111 fmt.Println("i=", i) } func main() { test() { i := 10 fmt.Printf("i=%v\n", i) } // i=12 错误 i

  • golang通过反射设置结构体变量的值

    如果需要动态设置struct变量field的情况下, 可以利用reflect来完成. 代码如下: package main import ( "fmt" "reflect" ) // 定义结构体Person type Person struct { Name string Age int } func main() { person := Person{} fmt.Println(person) // 修改前 { 0} pp := reflect.ValueOf(&

  • 浅谈golang并发操作变量安全的问题

    我就废话不多说了,大家还是直接看代码吧~ package main import ( "fmt" "time" "sync" "sync/atomic" ) func main() { test1() test2() } func test1() { var wg sync.WaitGroup count := 0 t := time.Now() for i := 0 ; i < 50000 ; i++ { wg.Add

  • golang 在windows中设置环境变量的操作

    安装完成后需要在系统环境变量中设置 GOPATH为项目目录 GOROOT为安装目录 path中设置好安装目录到bin目录 打开cmd,输入go env,出现如下配置生效 补充:Golang 环境变量须知 1.前言 无论你是使用 Windows.Linux 还是 Mac 操作系统来开发 Go 应用程序,在安装好 Go 安装语言开发工具之后,都必须配置好 Go 语言开发所要求的 环境变量,才算初步完成 Go 开发环境的搭建. 但对于一些初学者来说,可能不太明白 Go 语言中常用的环境变量的作用以及如

  • 解决golang 关于全局变量的坑

    学习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定义了但是没有使用

  • 解决 Golang VS Code 插件下载安装失败的问题

    最近开始学Go语言,但是在使用VS Code 编写Go的时候出现了插件无法下载的问题.最初我的解决办法也是从github下载再安装,但是我并不喜欢这种做法,因为我要在多台pc上使用VS Code编写Go,所以我觉要重复多次很麻烦,而且插件的安装也非常麻烦,我曾经一度想放弃学习Go语言,没错因为安装插件很麻烦.在经过我多次的查找最终找到了http://goproxy.cn/,这是Go的国内镜像,使用了这个就可以结局Go插件无法下载的问题. (http://goproxy.cn/ 文档简介,方便以后

  • 完美解决golang go get私有仓库的问题

    解决golang go get gitlab私有仓库的问题(1.13) 1. 问题描述 require ( git.xxxxxxx.com/middle/user v0.0.1 ) go mod tidy 导入包失败 go get git.xxxxxxx.com/middle/user 失败 go build 有CHECKSUM过程,无法编译 2. 现象分析 go get 不支持代码支持之外的仓库.并且git 调用链过程采取了https 下载过程如果机器设置了GOPROXY,会导致下载失败 编译

  • 解决Golang 中使用WaitGroup的那点坑

    sync.WaitGroup对于Golang开发者来说并不陌生,其经常作为多协程之间同步的一种机制.用好它势必会让你事半功倍,但是一旦错用将引发问题. 关于WaitGroup的使用网上有很多例子,在此就不做介绍了,我想说的是我在项目中使用WaitGroup遇到的坑. 在项目中,因为服务器有同步需求, 所以直接使用了WaitGroup,但是未考虑使用场景,结果在项目上线之后,高峰期的时候客户端经常出现卡顿,经过多方查找,才发现如果使用WaitGroup的时候,未启动单独的goroutine,那么极

  • 解决golang时间字符串转time.Time的坑

    字符串转时间一定要通过 time.ParseInLocation 不能直接用Parse todayZero, _ := time.ParseInLocation("2006-01-02", "2019-01-01 15:22:22" time.Local) 如果用了Parse,二者就会存在8小时时间差!!!! 补充:golang 常用的日期方法和时区的坑 import( "time" ) 1.获取当前时间 time.Now(),返回类型:time

  • 解决golang读取http的body时遇到的坑

    当服务端对http的body进行解析到map[string]interface{}时,会出现cli传递的是int类型,而服务端只能断言成float64,而不能将接收到的本该是int类型的直接断言为int cli func main(){ url:="http://127.0.0.1:8335/api/v2/submit" myReq:= struct { ProductId int `json:"product_id"` Mobile string `json:&q

  • 解决golang http.FileServer 遇到的坑

    上次写了一个2行实现一个静态服务器的文章 今天群里有个哥们是这么写居然返回的是404 见鬼了嘛?? http.handle("/js", http.FileServer(http.Dir("js")) http.ListenAndServe("8080", nil) 大概的意思就是绑定 路由为 js 的时候访问这个js 文件夹 看了一下确实代码上面没什么毛病.但是路径怎么修改 也不好使. 我把代码拿到我的 电脑上面运行 shitfuck 这是搞什

  • 解决golang中container/list包中的坑

    golang中list包用法可以参看这篇文章 但是list包中大部分对于e *Element进行操作的元素都可能会导致程序崩溃,其根本原因是e是一个Element类型的指针,当然其也可能为nil,但是golang中list包中函数没有对其进行是否为nil的检查,变默认其非nil进行操作,所以这种情况下,便可能出现程序崩溃. 1.举个简单例子 Remove()函数 package main import ( "container/list" "fmt" ) func

  • 解决Golang中ResponseWriter的一个坑

    在使用Context.ResponseWriter中的Set/WriteHeader/Write这三个方法时,使用顺序必须如下所示,否则会出现某一设置不生效的情况. ctx.ResponseWriter.Header().Set("Content-type", "application/text") ctx.ResponseWriter.WriteHeader(403) ctx.ResponseWriter.Write([]byte(resp)) 如1: ctx.R

  • 解决golang内存溢出的方法

    最近在项目中出现golang内存溢出的问题,master刚开始运行时只有10多M,运行几天后,竟然达到了10多个G.而且到凌晨流量变少内存也没有明显降低,内存状态呈现一种很不健康的曲线. 像这种情况肯定是golang内存溢出了,为此我持续排查了两天,终于找到问题所在,特此记录下. 准备工作 一台较好的环境测试机,单台运行无污染. 压测工具,无论服务是http还是websocket服务,都必须准备好压测工具模拟最真实的用户场景. 将master引入net/http/pprof包,通过http访问获

随机推荐