笔记 Go 作用域和生命周期
作用域和生命周期,往往被混为一谈,当然是两个概念。
概念
作用域
作用域是声明在程序文本中出现的区域,是一个编译时属性。
变量的生命周期
变量的生命周期是程序执行期间被程序的其他部分所引用的起止时间,它是个运行时属性。
举例
作用域
举 if 的例子: 有PHP开发经验的同学,需要注意区分开来。 比如
<?php
function f() {
return 1;
}
if ($x = f()) {// $x 赋值
var_dump($x);
} else {
var_dump("else");
}
var_dump($x);// 可以访问到 $x
Go中if作用域的例子:
func f() int {
return 12
}
func main() {
if x := f(); x == 1 {
fmt.Println("if", x)
} else {
fmt.Println("else", x)
}
fmt.Print(x) // 访问不到x,编译失败
}
生命周期
test.go
package main
import (
"fmt"
"hsd"
)
func main() {
cwd := hsd.GetCwd()
fmt.Printf("main %s\n", cwd)
}
cwd.go
package hsd
import (
"log"
"os"
)
var cwd string
func init() {
cwd, err := os.Getwd() // 这里有个隐藏的bug,但不影响编译通过
if err != nil {
log.Fatalf("%v", err)
}
log.Printf("init %s", cwd)
}
func GetCwd() string {
return cwd
}
这个例子的意图很明显,包hsd 初始化当前目录,提供一个对外函数GetCwd()返回包内未公开的cwd。
编译通过是没问题,但会发现test.go中并未打印出来。其实这是有bug的版本。
cwd, err := os.Getwd()
短变量声明的方式,是初始化函数内的局部变量,这种方式访问不到外部的cwd,因此包级别变量cwd未能更新。
修改的方式,就是函数内声明一个err变量,来避免使用短变量声明方式即可。