全局变量(类似JS)
在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑
这段代码原意是定义一个包内全局变量p,用foo()的返回值对p进行初始化,在bar中使用p。预期结果:bar()和main()中均输出5。但编译执行后的结果却是:Crash
var p *int
func foo() (*int, error) {
var i int = 5
return &i, nil
}
func bar() {
fmt.Printf("%p, %T\n", p, p) //output: 0x14dc80, 0×0, *int
fmt.Println(*p)
}
func main() {
fmt.Printf("%p, %T\n", p, p) //output: 0x14dc80, 0×0, *int
p, err := foo()
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%p, %T\n", p, p) //output: 0x2081c6020, 0x20818a258, *int
bar()
fmt.Println(*p)
}
问题出在操作符:=,对于使用:=定义的变量,如果新变量与同名已定义的变量不在同一个作用域中,那么 Go 会新定义这个变量。对于本例来说,main() 函数里的 p 是新定义的变量,会遮住全局变量 p,导致执行到bar()时程序,全局变量 p 依然还是 nil,程序随即 Crash
正确的做法是将 main() 函数修改为:
func main() {
var err error
p, err = foo()
if err != nil {
fmt.Println(err)
return
}
bar()
fmt.Println(*p)
}
函数的作用域
var f = func(i int) {
print("x")
}
func main() {
f := func(i int) {
print(i)
if i > 0 {
f(i - 1)
}
}
f(10)
}
参考答案及解析:10x。这道题一眼看上去会输出 109876543210,其实这是错误的答案,这里不是递归。假设 main() 函数里为 f2(),外面的为 f1(),当声明 f2() 时,调用的是已经完成声明的 f1()。f2还未完成声明。效果类似于下面的代码
var x = 23
func main() {
x := 2*x - 4
println(x) // 输出:42
}
for 语句的变量 a 是重新声明,它的作用范围只在 for 语句范围内
func main() {
a := 1
for i := 0;i<5;i++ {
a := a + 1
a = a * 2
}
fmt.Println(a)
}
方法内部的代码块
在golang中方法左括号{是不能换行的,不然编译不通过
func main()
{
}
代码块内部具有独立性质 (代码块内部定义的变量外部无法调用,但是代码块外定义的变量,代码块内可以调用)。代码块是要换行的
func main() {
x := 1
fmt.Println(x)
{ //代码块开头
fmt.Println(x)
i, x := 2, 2
fmt.Println(i, x)
} //代码块结尾
fmt.Println(x) // print ?
}