Go - Variable
内存边界
- 在编程语言中,为了方便操作内存特定位置的数据,使用
变量与特定位置的内存绑定 编译器或者解析器需要知道变量所能引用的内存区域边界- 动态语言
解析器可以在运行时通过对变量赋值的分析,自动确定变量的边界- 一个变量可以在运行时被赋予大小不同的边界
- 静态语言
编译器必须明确知道一个变量的边界才允许使用该变量- 但编译器无法自动分析,因此
边界信息必须由开发者提供 -变量声明 - 在具体实现层面,
边界信息由变量的类型属性赋予
- 动态语言
变量声明
Go 是静态语言,所有变量在使用前必须先进行
声明
声明:告诉编译器该变量可以操作的内存的边界信息(由变量类型信息提供)
通用
变量声明形式与主流静态语言的差异 - 将
变量名放在了类型前面(方便语法糖移除type)
如果没有
显式为变量赋予初值,Go编译器会为变量赋予类型零值
1 | var a int // a 的初值为 int 类型的零值 0 |
Go 的每种
原生类型都有其默认值,即类型零值
复合类型(array、struct)变量的类型零值为组成元素都为零值的结果
| 原生类型 | 类型零值 |
|---|---|
| 整型 | 0 |
| 浮点 | 0.0 |
| 布尔 | FALSE |
| 字符串 | "" |
pointer、interface、slice、channel、map、func |
nil |
变量声明块
1 | var ( |
多变量声明
1 | var a, b, c int = 1, 2, 3 |
变量声明块 + 多变量声明
1 | var ( |
语法糖
省略类型信息
省去 type -
var varName = initExpression
1 | var a = 13 |
编译器会根据右侧变量初值
自动推导变量的类型,并给变量赋予初值对应的默认类型
| Value | Type |
|---|---|
| 整型值 | int |
| 浮点值 | float64 |
| 复数值 | complex128 |
| 布尔值 | bool |
| 字符值 | rune |
| 字符串值 | string |
不使用默认类型,需要
显式地为变量指定类型(通用变量声明or显式类型转换)
1 | var a int32 = 1 |
省略类型信息的语法糖仅适用于:
变量声明的同时显式赋予变量初值
1 | package main |
1 | $ go build |
结合多变量声明,可以
同时声明多个不同类型的变量
a 类型为int,b 类型为rune,c 类型为string
1 | var a, b, c = 1, 'A', "abc" |
短变量声明
省去 var 和 type -
varName := initExpression
短变量声明中的变量类型也是由 Go 编译器
自动推导出来的
1 | func main() { |
短变量声明也支持多变量声明
1 | func main() { |
变量分类
包级变量
在
包级别可见的变量,如果包级变量是Exported,则为全局变量
包级变量
只能使用var关键的变量声明形式,不能使用短变量声明形式
初始化
饿汉
省略类型信息 -
var varName = initExpression
Go 编译器会自动根据 initExpression 结果值的类型,来确定 varName 的变量类型
1 | var ErrShortWrite = errors.New("short write") |
不使用默认类型,需要显式地为包级变量指定类型
1 | var a = 13 |
饱汉
虽然没有显式初始化,但同样有类型零值
1 | var a int32 |
声明聚类
将同一类的变量声明放在同一个
var 变量声明块中,提高代码可读性
1 | package net |
就近原则
是否将包级变量的声明
全部放在源文件的头部?
- 就近原则:尽可能在靠近
第 1 次使用变量的位置声明该变量 变量作用域最小化的一种实现手段
1 | var ErrNoCookie = errors.New("http: named cookie not present") |
一个包级变量在包内被
多次使用,还是放在源文件头部声明比较合适
局部变量
在 Go
函数或者方法体内声明的变量,仅在函数或方法体内可见
支持
短变量声明形式,局部变量特有,也是使用最多的一种声明形式
初始化
饱汉
延迟初始化,采用
通用的变量声明形式
省略类型信息声明和短变量声明,均不支持变量的延迟初始化- 因为 Go
编译器依赖变量初值,进行自动推导
- 因为 Go
- 因此,与
包级变量一样,如果是延迟初始化都只能采用通用的变量声明形式
1 | func main() { |
饿汉
显式初始化,采用
短变量声明形式
短变量声明形式是局部变量最常用的声明形式
1 | func main() { |
不使用默认类型,可以通过
类型转换,保持变量声明的一致性
1 | func main() { |
分支控制
尽量在分支控制时使用
短变量的声明形式
- 分支控制是 Go 中
短变量声明形式应用最广泛的场景 - Go 程序,
很少单独声明用于分支控制语句中的变量- 而是通过
短变量声明形式,将它们与if、for等控制语句融合在一起 - 在控制语句中
直接声明用于控制语句代码块中的变量
- 而是通过
短变量声明 + 分支控制,也很好地体现了就近原则,让变量的作用域最小化
1 | func LastIndexAny(s, chars string) int { |
声明聚类
设计良好的函数或方法,都追求单一职责,一般规模都不大- 因此,很少需要应用
var 变量声明块来聚类局部变量
1 | func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) { |













