写点什么

golang 中的变量阴影

作者:六月的
  • 2022-10-19
    上海
  • 本文字数:2118 字

    阅读完需:约 1 分钟

索引:https://waterflow.link/articles/1666019023270


在 Go 中,在块中声明的变量名可以在内部块中重新声明。 这种称为变量阴影的原理很容易出现常见错误。


以下示例显示了由于变量阴影而导致的意外副作用。 它以两种不同的方式获取课件信息,根据 printLog 这个布尔值,判断是否打印日志而走到不同的代码分支:


package main
import "fmt"
type Courseware struct { Id int64 Name string Code string}
func main() { printLog := false var courseware *Courseware // 1
if printLog { courseware , err := getCoursewareAndLog() // 2 if err != nil { fmt.Println("get courseware err: ", err) } fmt.Println(courseware) // 3 } else { courseware, err := getCourseware() // 2 if err != nil { fmt.Println("get courseware err: ", err) } fmt.Println(courseware) // 3 }
fmt.Println(courseware) // 4}
func getCoursewareAndLog() (*Courseware, error) { fmt.Println("打印日志。。。") return &Courseware{ Id: 1, Name: "多媒体课件", Code: "CW100", }, nil}
func getCourseware() (*Courseware, error) { return &Courseware{ Id: 2, Name: "多媒体课件1", Code: "CW101", }, nil}
复制代码


我们可以分析下上面的代码:


  1. 首先我们定义了一个 courseware 变量,初始化为指向 Courseware 的指针,默认为 nil

  2. 我们在 if 代码块的内部调用了获取课件详情的方法,并返回 Courseware 的指针和 error。我们仍然使用变量 courseware 去接收,注意这里我们使用了短变量声明的操作:=,说明在代码块内部我们重新声明了一个变量 courseware,这个并不是外部的 courseware 变量。

  3. 我们在代码块内部打印下获取课件详情的信息

  4. 我们在在 if 代码块外部打印下获取课件详情的信息


如果现在我们用的是 PHP 语言,那这个绝对不会出现任何问题。if 代码块内部会打印出获取课件的详情,外部也会打印出获取课件的详情。对应上面代码中的 3、4。毕竟 PHP 是世界上最好的语言么。


但是在上面的结果中,3 会正常打印课件详情,4 会打印 if 代码块外部的 courseware,所以是 nil。


我们看下打印的结果:


go run 1.go&{2 多媒体课件1 CW101}<nil>
复制代码


这就是所谓的变量阴影。


那我们该如何修改上面的代码使程序变得正常呢?


其实有 2 种方式修改:


  1. 增加一个临时变量


   package main      import "fmt"      type Courseware struct {     Id int64     Name string     Code string   }      func main()  {     printLog := false     var courseware *Courseware // 1        if printLog {       cw , err := getCoursewareAndLog() // 2       courseware = cw // 增加临时变量       if err != nil {         fmt.Println("get courseware err: ", err)       }       fmt.Println(courseware) // 3     } else {       cw, err := getCourseware() // 2       courseware = cw // 增加临时变量       if err != nil {         fmt.Println("get courseware err: ", err)       }       fmt.Println(courseware) // 3     }        fmt.Println(courseware) // 4   }      func getCoursewareAndLog() (*Courseware, error) {     fmt.Println("打印日志。。。")     return &Courseware{       Id: 1,       Name: "多媒体课件",       Code: "CW100",     }, nil   }      func getCourseware() (*Courseware, error) {     return &Courseware{       Id: 2,       Name: "多媒体课件1",       Code: "CW101",     }, nil   }
复制代码


看下打印结果,正常输出:


   go run 1.go   &{2 多媒体课件1 CW101}   &{2 多媒体课件1 CW101}
复制代码


  1. 不使用:=,err 在外部初始化


   package main      import "fmt"      type Courseware struct {     Id int64     Name string     Code string   }      func main()  {     printLog := false     var courseware *Courseware // 1     var err error // err放到外层        if printLog {       courseware , err = getCoursewareAndLog() // 2 =号赋值       if err != nil {         fmt.Println("get courseware err: ", err)       }       fmt.Println(courseware) // 3     } else {       courseware, err = getCourseware() // 2 =号赋值       if err != nil {         fmt.Println("get courseware err: ", err)       }       fmt.Println(courseware) // 3     }        fmt.Println(courseware) // 4   }      func getCoursewareAndLog() (*Courseware, error) {     fmt.Println("打印日志。。。")     return &Courseware{       Id: 1,       Name: "多媒体课件",       Code: "CW100",     }, nil   }      func getCourseware() (*Courseware, error) {     return &Courseware{       Id: 2,       Name: "多媒体课件1",       Code: "CW101",     }, nil   }
复制代码


看下结果,正常输出:


   go run 1.go   &{2 多媒体课件1 CW101}   &{2 多媒体课件1 CW101}
复制代码


用户头像

六月的

关注

还未添加个人签名 2019-07-23 加入

还未添加个人简介

评论

发布
暂无评论
golang中的变量阴影_golang_六月的_InfoQ写作社区