在之前已经认识了数据类型,要使用数据类型就需要配合变量/常量,通过标识符命名即可指向对象存储数据。
变量/常量是计算机语言中使用方便的占位符,属于一种抽象概念。
命名由字母、数字、下划线组成,其中首个字符不能为数字,即前面提到的:标识符。
变量声明
声明变量的一般形式是使用 var 关键字,实际上有多种写法。
第一种 使用 var 关键字并指定变量类型。
如果没有初始化,则变量默认为零值。
Go 语言中,变量都存在零值,例如:
// 声明一个变量,指定数据类型并初始化
var initStrA string = "a"
// 声明一个变量,并指定数据类型,默认有零值:空字符串
var initStrB string
第二种 编译器根据值自行推断变量类型。
// 声明一个变量并初始化,编译器自动推断类型
var initStrC = "c"
第三种
短句声明,属于一种语法糖,不使用 var 关键字,直接使用 :=
声明并赋值。
// 声明变量 initVal 赋值为 1
initVal :=1
// 例如在 for 语句中声明变量
for initInt := 1; initInt < 3; initInt++ {
fmt.Println(initInt)
}
多变量声明
多变量的声明方式还是上面提到的三种,不一样的是可以同时声明多个变量
例子
// 声明多个变量名,接着指定类型(同一类型)
var val1, val2, val3 int
// 多个值在一个语句赋值
val1, val2, val3 = 1, 2, 3
// 声明多个变量名,接着指定类型(同一类型)并完成初始胡
var val1, val2, val3 int = 1, 2, 3
// 声明多个变量名并完成初始胡(编译器自动推断类型,不限定类型)
var val1, val2, val3 = 1, 2, "3-Str"
// 短句声明
val1, val2, val3 := 1, 2, 3
常量是一个简单值的标识符,同变量的差异是,在程序运行过程中常量不会被修改。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的声明使用关键字 const
。
// 声明常量(指定类型)
const constStr string = "Const String"
// 声明常量(编译器推断类型)
const constStr = "Const String"
一般使用关键字 const
配合 iota
快捷实现类似枚举的能力。
const (
Unknown = 0
Female = 1
Male = 2
)
iota
属于一个特殊常量,可以认为由编译器自动确定值的常量。
iota 在 const 关键字出现时将被重置为 0(通常 const 用在内部的第一行)。
const 中每新增一行常量声明将使 iota 计数加一,也可以说是 const 语句块中的行索引赋值给指定常量。
const (
// 0
a = iota
// 1
b = iota
// 2
c = iota
)
// 简写
const (
// 0
a = iota
// 1
b
// 2
c
)
// const 配合 iota 赋值时,也可以进行特殊指定,或者恢复计数赋值
const (
a = iota // iota --> 0
b // iota --> 1
c = "c" // 独立值 c,iota --> 2
d // 独立值 c,iota --> 3
e = "e" // 独立值 e,iota --> 4
f // 独立值 e,iota --> 5
g = iota // iota --> 6
h // iota --> 6
)
// 同样 iota 这个值也可以 const 中用于计算
const (
a = iota * 3 // 0
b // 3
c // 6
)
值类型
像 int32、float32、bool 和 string 这些基本类型都属于值类型。
例如语句 var valInt int32 = 2
中,valInt 指向一个内存地址(0xc00012207c),或者说是内存地址的别名。在这个内存中存放的就是值 2。
使用符号 =
,对值类型进行赋值时,是将内存中的值进行了拷贝存入了新的一块内存。
从下面的例子可以看出,值类型赋值后的两个变量是两块内存。
var valInt int32 = 2
var valIntBack int32 = valInt
// 0xc0000a607c
fmt.Println(&valInt)
// 0xc0000a6080
fmt.Println(&valIntBack)
引用类型
引用类型的变量的实现主要分为两部分,以我电脑 64 位为例。
var valMap map[string]int = make(map[string]int)
valMap 是内存地址 0xc00000a030 的别名,在这个内存块中记录的是另一块内存的地址:0xc000112510。
地址 0xc000112510 对应的内存块才是存储的数据。贴一个结构体的内存结构图示意:
从下面例子输出的内存地址就可以确定这种结构。
var valMap map[string]int = make(map[string]int)
valMap["a"] = 1
var valMapBack = valMap
// 0xc000112510
fmt.Printf("%p\n", valMap)
// 0xc000112510
fmt.Printf("%p\n", valMapBack)
// 0xc00000a030
fmt.Printf("%p\n", &valMap)
// 0xc00000a038
fmt.Printf("%p\n", &valMapBack)