Go 语言变量的作用域

Wolther47 · · 2049 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

声明与赋值

在 Go 语言中,声明一个变量可以通过 var name type = expression 做到,但同时,Go 也支持称为短变量声明的形式 name := expression

出于方便的因素,Go 支持多重短变量声明 name, age := expression1, expression2,这个用法容易同多重变量赋值混淆 name, age = expression1, expression2

另外,也存在一个 new 函数,通过 new(T) 来创建一个 T 类型的对象。

如果使用多重短变量声明,一旦在同一作用域内该变量已经声明过,则 Go 语言实际上会执行一个赋值操作,下面举个例子。

package main

import (
    "fmt"
)

var name string // 包级变量 name

func main() {

    fmt.Print(&name) // 打印包级变量 name 的地址

    var score int // 声明一个 score 的 int 变量

    name, score := "Wolther47", 100
    // 这一行中,有两个要点:
    // 1. score:score 在之前被声明为一个 int 变量,则对于变量 score,`:=` 相当于一个赋值语句
    // 2. name:如果有一个变量在当前的作用域中,没有进行过声明,则 Go 就会进行声明,而不是向上寻找,
    //    即,此处的 name 会覆盖包级别变量 name.

    fmt.Printf("%s's score is %d.\n", name, score)

    fmt.Print(&name)
}

随即引出的问题是,Go 语言如何界定所谓的作用域

这是一个比较重要的问题,由于 Go 会在编译时检查每个变量是否使用,一旦出现未使用的变量,就会失败。如果不能理解作用域,有可能会带来一些不明所以的编译错误。

Blocks and Scopes in Golang 这篇文章里,作者列出了 Go 的四种代码块:

  • universe block,包含项目的所有源代码
  • package block,包含项目的所有源代码,除导入的包
  • file block,包含该文件内所有的源代码,包括导入的包
  • lexical block[1],包含在花括号内的源代码,但是 composite literals[2] 以及类型定义 type definitions 不构成 lexical block

对于 lexial block,有一些例外:

  • 函数的传入参数,以及 return 的结果,尽管在函数体的花括号外,但是它们的作用域视为函数体内部
  • 选择、循环语句的 ifswitch 以及 for 会打开两个 lexical block,一个为显式,另一个为隐式,隐式的作用域嵌套显式的作用域。原文此处讲的比较抽象,下面以 if 为例直接上代码
package main

import (
    "fmt"
)

type Cat struct {
    Name    string
    Age     int
    Servant string
}

func getCat() Cat {
    return Cat{"Sushi", 3, "Wolther47"}
}

func main() {

    if cat := getCat(); cat.Servant == "Wolther47" {
        // cat 这个变量的作用域从 if 关键词开始,一直到最后的花括号结束

        words := "Yep" // words 这个变量的作用域只在花括号内
        fmt.Printf("I've served %s for %d years.\n%s\n", cat.Name, cat.Age, words)
    }

}
  • else 同样也会打开一个 lexical block,并且显然,这个 block 应该和 if 显式打开的 lexical block 为同级兄弟关系,并且同样被嵌套在 if 的隐式作用域里
  • switchcase (或者 default)同样也会打开一个 lexical block,嵌套在 switch 隐式打开的作用域里

另外,强推这篇文章,作者比较详尽地归纳了 block,同时也整理了 block 的嵌套以及不同元素该在何处声明的问题,此处不再赘述。

本文发布在 Wolther47 的博客上,本作品采用知识共享署名 4.0 国际许可协议进行许可


  1. 这篇文章的作者使用 local block 来表示,本文遵循 The Go Programming Language,依旧使用 lexical block

  2. 机械工业出版社的 The Go Programming Language 翻译成「复合字面量」,个人不喜欢这种翻译,不予采用


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:Wolther47

查看原文:Go 语言变量的作用域

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2049 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传