变量 Variables

应用程序中业务逻辑的实现是通过数据的改变来体现的。例如:需要完成一个排序业务逻辑,一个无序的列表,变成一个有序的列表,意味着程序实现了相应的功能。

数据是应用程序操作的核心,程序就是用来操作数据来实现具体功能的。

在程序设计中,使用变量来引用存储数据,通过对变量可以获取该数据,进而对该数据进行操作。变量记录的值的存储地址。

Go 语言是强类型语言,变量合理值的集合取决于变量的类型。变量类型在变量声明时确定。

变量由标识符 identifier、类型 type 和存储值 value 构成。变量对应内存中一块特定空间,存储变量值,变量标识符存储该值地址,通过地址操作对应值。示例图:

变量示意图

变量声明 Variable declarations

变量声明用于创建一个或多个变量,为变量绑定标识符,同时提供类型和初始值。变量声明意味着程序在内存中为变量开辟了空间,用于存储变量值,通过提供标识符来引用该存储空间地址。

语法如下:

var 标识符 类型 // 声明单个变量,指定类型,初始值为类型零值
var 标识符 类型 =  表达式 // 声明单个变量,指定类型,指定初始值
var 标识符 = 表达式 // 声明单个变量,指定初始值,利用推导类型确定类型
var 标识符1, 标识符2, ... 类型 // 声明多个同类型的变量,初始值为类型零值
var 标识符1, 标识符2, ... 类型 = 表达式1, 表达式2, ... // 声明多个同类型的变量,指定初始值
var 标识符1, 标识符2, ...  = 表达式1, 表达式2, ... // 声明多个变量,利用推导类型确定类型

// 多声明语句简化
var (
    标识符 类型 // 声明单个变量,指定类型,初始值为类型零值
	标识符 类型 =  表达式 // 声明单个变量,指定类型,指定初始值
	标识符 = 表达式 // 声明单个变量,指定初始值,利用推导类型确定类型
	标识符1, 标识符2, ... 类型 // 声明多个同类型的变量,初始值为类型零值
	标识符1, 标识符2, ... 类型 = 表达式1, 表达式2, ... // 声明多个同类型的变量,指定初始值
	标识符1, 标识符2, ...  = 表达式1, 表达式2, ... // 声明多个变量,利用推导类型确定类型
) // 一个var关键字,同时定义多个变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

演示:

var v1 int
var v2 int = 42
var v3 = 42
var v4, v5 int
var v6, v7 int = 42, 1024
var v8, v9 = 42, "Hank"

// 多声明语句简化
var (
    v1 int
	v2 int = 42
	v3 = 42
	v4, v5 int
	v6, v7 int = 42, 1024
	v8, v9 = 42, "Hank"
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

声明变量时,要提供变量需要的标识符、类型和初始值。若未指定指定初始值,使用类型的零值;若未指定类型,利用表达式值做类型推导来确定变量类型。总之,变量声明要保证变量一定具有值和类型。

具体的类型零值参考类型章节。

强类型 Strong type

Go 属于强类型语言。指的是变量必须具有特定类型,而且只能存储该类型数据。

强类型优势如下:

  • 编译时完成表达式类型检测,保证类型匹配。
  • 运算时开销降低。
  • 代码更严谨,代码质量更高。

类型推导 Deducing type

声明变量时若未指定类型,通过值表达式推导出变量类型,称之为类型推导。

通常值可以确定其类型,例如 "hank" 是字符串的字面量语法,就可以确定类型为 string 类型。

若值不能确定其具体类型,则使用其默认类型。整数,浮点数,复数都具有默认类型,分别为:int, float64, complex128。例如整数值42可作为 int, uint, int8, uint8... 等一系列整数类型的值,若利用42推导类型,其默认类型是 int ,因此对应的变量也被设定为 int 类型。

演示:

var v = 42 // 整数42的默认类型为 int,进而推导 v 为 int 类型,而不是其他的整型(int8, uint 等)
var s = "Go" // "Go" 是 string 型的字面量,推导 s 为 string 类型
1
2

零值 The zero value

当声明变量但未提供初始化值时,将使用一个默认值进行初始化,该默认值称之为零值。零值是基于类型的,不同类型具有不同的零值,见下表:

类型 零值
布尔 false
整型集 0
浮点数型集(float32, float64) 0.0
字符串 "" 空字符串,len() 为0
指针、函数、接口、切片、信道、映射 nil nil 表示空指针

短变量声明 Short variable declarations

短变量声明,是常规变量声明的快捷语法。利用类型推导,通过值确定来类型。

运算符 := 用于短变量声明,语法:

标识符 := 表达式 // 声明单个变量
标识符1, 标识符2... := 表达式1, 表达式2... // 声明多个变量
1
2

演示:

v := 42 // int
v1, v2 := 42, "Go" // int, string
1
2

使用 := 运算符要求左边变量列表,至少有一个未声明的变量。已声明变量作为左值表示为其赋值。这意味着,未声明变量和已声明变量可同时出现在 := 运算符左边,表示声明未声明变量,同时为已声明变量赋值。

演示:

// 没有未声明变量触发错误
v1, v2 := 42, "Go"
v1, v2 := 1024, "GoLang" // error: no new variables on left side of :=
1
2
3
// 未声明和已声明变量同时使用 
v1, v2 := 42, "Go"
//v1, v2 := 1024, "GoLang",  // : no new variables on left side of :=
v1, v2, v3 := 1024, "GoLang", "Hank" // 成功定义 v3。同时 v2, v1 被赋值
1
2
3
4

注意,短变量声明语句不是预处理语句,因此不能在函数外使用。相对于 var 属于预处理语句,因此可在函数外使用,用于定义全局变量。

演示:

func main() {
} // 函数结束
var g = "global" // 可行的
g := "global" // : syntax error: non-declaration statement outside function body
1
2
3
4

推荐使用短变量声明。

空白变量标识符,Blank identifiers

变量支持空白变量标识符,就是下划线_,空白变量标识符不能绑定指定的数据。主要用于在多值声明或多值赋值环境中,对不需要使用的变量占位,来保证位置的对应关系。

典型的使用场景演示:

// 函数 FuncIdentifier() 返回三个值,我们仅需要第一,第三个
result1, _, result2 = FuncIdentifier() 
1
2

语法细节

先声明后使用

下列语法会触发错误,演示:

fmt.Println(v) // error: undefined v
var v = "Go" // 定义变量
1
2

定义的变量必须要被使用

下列语法会触发错误,演示:

var v = "Go"
.\variable.go:31:6: v declared but not used
1
2

该策略,保证程序足够严谨,也是 Go 语言的一个优势。

赋值运算