第十三回:Go 语言变量作用域

哪里是我的地盘?(作用域详解)
华夫人
华夫人: 华府规矩森严!有些东西是大家的(全局),有些东西是你房里私有的(局部)。 还有,想把东西拿出去卖(导出给别的包用),名字必须得大写

1. 🛏️ 私人厢房 (局部作用域)

定义在函数内部,或者 if/for/switch{} 代码块里的变量。出了这个 {} 就没人认识它了。

9527
9527: 我藏了一只烤鸡翅在我的房间里(if 代码块)。出了房间如果还想吃,那是不可能的!
func main() {
    // 这是一个局部变量,只在 main 里活着
    var myMoney = 100 

    if true {
        // 这个 chicken 只在 if 块里活着
        chicken := "烤鸡翅" 
        fmt.Println("我在吃:", chicken)
    }
    // fmt.Println(chicken) // ❌ 报错!出了房间,鸡翅就没了
}

2. 🏠 华府大院 (包级作用域)

定义在函数外面的变量,整个包(package)的文件都能访问。如果是全局变量,甚至可以跨文件访问。

package main

var 华府大门 = "开着" // 全局变量

func main() {
    fmt.Println(华府大门) // 可以访问
}

func other() {
    fmt.Println(华府大门) // 也可以访问
}

3. 📦 出口贸易 (导出规则 - 非常重要!)

在 Go 语言中,没有 public / private 关键字。首字母大小写决定了一切!

秋香
秋香: 9527,你要记住,如果你的名字叫 tangBoHu (小写),你就只能呆在这个包里做下人;
如果你改名叫 TangBoHu (大写),你就是江南四大才子,全天下(所有包)都认识你了!
// 这个变量别的包可以用 (Public)
var Version = "1.0"

// 这个变量只有本包可以用 (Private)
var secret = "唐伯虎的身份"

4. 🌑 鸠占鹊巢 (变量遮蔽 Shadowing)

如果局部变量和全局变量同名,局部变量会遮蔽全局变量。也就是“县官不如现管”。

唐伯虎
唐伯虎: 嘿嘿,在华府外面我是“唐伯虎”(全局变量),但进了华府(局部作用域),我就用“9527”(局部变量)这个名字遮蔽了原来的身份!
var Name = "唐伯虎" // 全局身份

func main() {
    fmt.Println(Name) // 输出:唐伯虎
    
    // 进入局部作用域(华府)
    if true {
        Name := "9527" // 定义了一个新的局部变量 Name,遮蔽了全局的
        fmt.Println(Name) // 输出:9527
    }
    
    fmt.Println(Name) // 出了 if 块,又回到了全局,输出:唐伯虎
}
⚠️ 走火入魔警告 (短变量声明陷阱):

最容易犯错的地方是 if 语句里用 :=

count := 0
if true {
    // 这里的 count 是全新的局部变量!不是外面那个!
    count := 10 
    fmt.Println("里面:", count) // 10
}
fmt.Println("外面:", count) // 0 (外面那个根本没变!)

解决办法: 如果想修改外面的变量,千万别用 := (声明+赋值),要用 = (赋值)。

🎯 练功房(找不同)

分析下面的代码,为什么报错?

package main
import "fmt"

func main() {
    if true {
        x := 10
        fmt.Println(x)
    }
    fmt.Println(x) // 这里为什么报错?
}

任务: 解释报错原因。

答案: undefined: x

解析: 变量 x 是在 if 的大括号里定义的,它的寿命只有那么短。出了大括号,它就灰飞烟灭了。这就是块级作用域