声明与赋值
在 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 的结果,尽管在函数体的花括号外,但是它们的作用域视为函数体内部
- 选择、循环语句的
if
,switch
以及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
的隐式作用域里 -
switch
的case
(或者default
)同样也会打开一个 lexical block,嵌套在switch
隐式打开的作用域里
另外,强推这篇文章,作者比较详尽地归纳了 block,同时也整理了 block 的嵌套以及不同元素该在何处声明的问题,此处不再赘述。
本文发布在 Wolther47 的博客上,本作品采用知识共享署名 4.0 国际许可协议进行许可
-
这篇文章的作者使用 local block 来表示,本文遵循 The Go Programming Language,依旧使用 lexical block ↩
-
机械工业出版社的 The Go Programming Language 翻译成「复合字面量」,个人不喜欢这种翻译,不予采用 ↩
有疑问加站长微信联系(非本文作者)