03、变量
Go 变量核心特性
1. 声明方式区分作用域
var:全局、函数内都能用;可只声明不赋值:=短变量:仅函数内部,必须直接赋值,不能单独声明
2. 自动零值初始化
只要用 var 声明不赋值,自动赋予对应类型零值,无未定义垃圾值:
- 数值:0 / 0.0
- bool:false
- string:空字符串
"" - 指针、切片、map、chan、接口:
nil
3. 强类型,类型不可变更
变量类型一旦确定,不能存其他类型数据
a := 10
a = "abc" // 编译报错
4. 声明后必须使用
局部变量只定义不使用,直接编译失败;全局变量允许只声明不用。
匿名变量 _ 例外,专门用来丢弃返回值。
5. 命名导出特性(大小写控制访问权限)
- 首字母小写:包内私有,其他包无法访问
- 首字母大写:导出,跨包可读取修改
6. 作用域隔离
- 全局变量:包级别,所有函数共享
- 局部变量:函数 / 代码块
{}内有效,出块销毁 - 内层变量同名会遮蔽外层变量
7. 短变量声明特殊规则
同一行赋值至少要有一个新变量才能复用旧变量:
a, b := 1, 2
a, b := 3, 4 // 报错,无新变量
a, c := 3, 4 // 合法,c是新变量
8. 多变量并行赋值
支持一次性交换、接收多返回值,无需中间变量
a, b := 10, 20
a, b = b, a
9. 可批量块声明
用 var() 批量定义一组变量,整洁统一
var (
x int
s string
flag bool
)
10. 区分变量与常量
变量可重复修改;const 常量定义后只读,不能修改。
Go 变量完整用法
一、变量声明三种方式
1.标准声明 var(可全局 / 函数内)
// 格式 var 变量名 类型
var a int
var b string
var c bool
// 声明并赋值
var num int = 10
var str string = "hello"
// 多变量同类型
var x, y int = 1, 2
// 块声明(批量)
var (
age int = 20
name string = "张三"
)
2.类型推导(省略类型,自动识别)
var num = 100 // 自动int
var s = "golang"// 自动string
3.短变量声明 :=(仅函数内部可用,最常用)
func main() {
a := 10
b := "test"
c, d := 1, true
// 同一行至少一个新变量才能重复赋值
c, e := 99, "new"
}
二、变量规则
1.命名规范
- 字母 / 数字 / 下划线,不能数字开头
- 小驼峰:userName(包内私有);大驼峰:UserName(导出,外部包访问)
2.零值机制:Go 变量声明默认赋零值,不用手动初始化
| 类型 | 零值 |
|---|---|
| int | 0 |
| float | 0.0 |
| string | "" |
| bool | false |
| 指针 / 切片 /map | nil |
var n int
fmt.Println(n) // 输出 0
3.变量必须使用:声明后不编译报错
4.作用域
- 全局变量:函数外,整个包生效
- 局部变量:函数 / 代码块
{}内,块结束销毁 - 内层变量同名会遮蔽外层变量
三、多变量交换
a, b := 10, 20
a, b = b, a // 不用中间变量交换
四、匿名变量 _(丢弃值,不占用内存)
// 函数返回两个值,只取第二个
_, res := test()
五、完整示例代码
package main
import "fmt"
// 全局变量
var global int = 666
func main() {
// 短声明
name := "Go语言"
age := 18
// var推导
var score = 95.5
// 多变量
var m, n int = 1, 3
m, n = n, m
fmt.Println(global, name, age, score, m, n)
}
示例 1:全局变量 + 函数局部变量同名遮蔽
package main
import "fmt"
// 全局变量 num
var num int = 100
func main() {
// 局部变量 num,同名,遮蔽全局
num := 20
fmt.Println(num) // 输出:20(使用局部,看不到全局)
// 想要访问全局只能换名,无法在块内直接取外层同名变量
}
示例 2:函数局部 + 代码块内层变量遮蔽
package main
import "fmt"
func main() {
name := "外层张三"
if true {
// 内层同名变量,遮蔽外层 name
name := "内层李四"
fmt.Println(name) // 内层李四
}
// 代码块结束,内层销毁,恢复外层
fmt.Println(name) // 外层张三
}
示例 3:多层嵌套连续遮蔽
package main
import "fmt"
func main() {
a := 1
fmt.Println(a) // 1
{
a := 2
fmt.Println(a) // 2
{
a := 3
fmt.Println(a) // 3
}
fmt.Println(a) // 2
}
fmt.Println(a) // 1
}
示例 4:容易踩坑的短变量遮蔽(高频错误)
package main
import "fmt"
func main() {
x := 10
if true {
// 错误写法::= 新建同名x,不是修改外层x
x, y := 20, "test"
fmt.Println(x) // 20(内层)
}
fmt.Println(x) // 10(外层没变)
// 正确修改外层:不用 :=,直接 =
if true {
var y string
x, y = 30, "ok"
fmt.Println(x) // 30
}
fmt.Println(x) // 30
}
示例5:匿名变量示例 函数多返回值,丢弃其中一个
package main
import "fmt"
// 返回两个值
func getInfo() (int, string) {
return 20, "张三"
}
func main() {
// 只需要姓名,舍弃年龄
_, name := getInfo()
fmt.Println(name) // 张三
// 只需要年龄,舍弃姓名
age, _ := getInfo()
fmt.Println(age) // 20
}
示例6:匿名变量 range 遍历,丢弃下标 / 值
package main
import "fmt"
func main() {
arr := []int{10,20,30}
// 只要值,不要索引
for _, v := range arr {
fmt.Println(v) //10 20 30
}
// 只要索引,不要值
for i, _ := range arr {
fmt.Println(i) //0 1 2
}
}
示例7:匿名变量 map 取值,忽略是否存在标识
package main
import "fmt"
func main() {
m := map[string]int{"a":1}
// 只取value,不在乎key是否存在
val, _ := m["a"]
fmt.Println(val) //1
}
示例8:匿名变量 函数调用只执行,不接收返回值
package main
import "fmt"
func test() int {
fmt.Println("执行函数")
return 99
}
func main() {
// 接收返回值但直接丢弃
_ = test() //执行函数
}
/*
① test()
仅单纯调用函数,完全不接收返回值,返回值直接被运行时丢弃,无赋值操作。
② _ = test()
接收函数返回值,再赋值给匿名变量 _,显式处理返回值,再主动舍弃。
推荐 _ = test() 的场景
test():无返回值 / 不在意返回 → 简写
_ = test():有返回值,主动舍弃,代码表意清晰,工程推荐
函数存在返回值(尤其包含 error),你明确选择不校验结果:
// 文件关闭、资源释放,规范显式丢弃错误
_ = resp.Body.Close()
*/