【Go 语言学习笔记】变量和常量

发表于 2023-07-04

在之前已经认识了数据类型,要使用数据类型就需要配合变量/常量,通过标识符命名即可指向对象存储数据。

命名

变量/常量是计算机语言中使用方便的占位符,属于一种抽象概念。

命名由字母、数字、下划线组成,其中首个字符不能为数字,即前面提到的:标识符

变量

变量声明

声明变量的一般形式是使用 var 关键字,实际上有多种写法。

第一种 使用 var 关键字并指定变量类型。

如果没有初始化,则变量默认为零值。

Go 语言中,变量都存在零值,例如:

  • 字符串的零值是:""(空字符串)
  • 数值类型的零值是:0
  • 布尔类型的零值是:false
  • 还有 nil 也是某一些类型的零值
// 声明一个变量,指定数据类型并初始化
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)