我们在使用golang
时,是否遇到过以下写法:
package main
import "fmt"
func fn() (string, error) {
return "test", fmt.Errorf("test error")
}
func main() {
name := "main"
if name, err := fn(); err != nil {
fmt.Println("fn return name = ", name, err)
}
fmt.Println("name = ", name)
}
上面的输出,有时我们的期望输出为
fn return name = test, test error
name = test
但我们得到的输出结果为
fn return name = test, test error
name = main
这就是我们今天要说的主角 变量作用域
在golang中变量作用域分为:
- 本地局部变量
- 全局变量
- 参数变量
本地局部变量
定义:在函数或者在语义块(if/for等)中定义的变量
生效范围:定义在函数里面则在整个函数范围有效; 定义在语义块,则在整个语义块生效
func main() {
name := "main" // main函数内的局部变量
if true {
name := "in if" // 条件语义块中定义的变量
}
for .... {
name := "in for" // for 语义块中定义的变量
}
{
name := "in block" // 普通语义块中定义的变量
}
}
从上面几种情况看,局部变量的定义范围就是看所在的 {}
的范围
全局变量
定义:函数外部定义的变量都属于全局变量;全局变量声明必须以 var 开头
生效范围:当前 package 内,如果想要其他 package 访问,全局变量以大写开头
package main
var name = "这里定义的为本包的全局变量"
var Name = "这里定义的为可以包外访问的全局变量"
func main() {
}
参数变量
定义:函数调用时传递的变量
生效范围:函数范围(但是有可能会可变传入参数的值,取决于传递的参数的类型)
如果传入的为基本数据类型byte、bool、int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、float32、float64、string
和struct、slice
时为值传递,生效范围就是本函数;但传入了map、func、指针
等类型为地址传递,生效范围就不只传入的函数本身
再回头分析最上面的案例
// 这里name为if 语义块中定义的局部变量,所以不会改变 if 语义块外面的值
if name, err := fn(); err != nil {
fmt.Println("fn return name = ", name, err)
}
我们可以通过以下代码让其生效
package main
import "fmt"
func fn() (string, error) {
return "test", fmt.Errorf("test error")
}
func main() {
name := "main"
var err error
// 这里直接赋值,没有产生新的定义
if name, err = fn(); err != nil {
fmt.Println("fn return name = ", name, err)
}
fmt.Println("name = ", name)
}
有疑问加站长微信联系(非本文作者)