本文内容是本人对Go语言的变量、常量、数组、切片、映射、结构体的备忘录,记录了关键的相关知识点,以供翻查。
文中如有错误的地方请大家指出,以免误导!转摘本文也请注明出处:Go语言备忘录:基本数据结构,多谢!
参考书籍《Go语言圣经》、《Go语言实战》、《Go语言学习笔记》等
一、变量
- 变量是一段或多段用来存储数据的内存;
- 变量总是有固定的数据类型,类型决定了所占内存的长度和存储格式;
- 编译后的代码使用变量的内存地址来访问数据,而不是变量名;
- 简短变量声明只能在函数内声明(局部变量),var声明方式则无限制(但一般用于声明未显式初始化的变量);
- 声明同一作用域中的同名变量时,将回退为赋值,即重用该变量(必须至少有一个新变量定义);
- 而声明不同作用域的同名变量则为重新定义(覆盖);
var q int
var y = 453
var (
n,m = 134,"srf"
n1,m1 int
)
func f1() {
n,m := 25,"sss"
n,m1 := 34,"yyy"
fmt.Println(n,m,m1)
n = n+5 //赋值表达式中,首先计算右值
//“_”空标识符用来临时规避编译器对未使用变量和导入包的错误检查
if _,ok := add1(n);ok {
fmt.Println(n)
}
}
func add1(n int) (int, bool) {
return n+1,true
}
二、常量、枚举
- 常量是一个不可改变的值,它可以为字面量,或编译器能计算出结果的表达式。未使用的常量不会引起编译错误;
- 在常量组中如不指定类型和初始值,则与上一行非空常量右值相同;
- 常量会被编译器在预处理阶段直接展开,作为指令数据使用,所以无法取常量的地址;
const i = 5
const (
x byte = 1
x1
x2 //x1,x2均为1
s = "abs"
s1 //s1=“abc”
)
const (
_,_ int = iota,iota*3 //0,0*3 忽略值,并显式指定类型为int
k1,k2 //1,1*3
l1,l2 //2,2*3
o1,o2 = 5,6 //中断iota自增
r1,r2 //5,6 同上一行
e1,e2 = iota,iota*3 //5,5*3 恢复iota自增,按行递增
)
//枚举
type color byte
const (
blue color = iota
red
green
)
func main() {
t:= blue
fmt.Println(t) //0
//fmt.Println(&i) //错误:无法对常量取地址 cannot take the address of i
}
三、数组
- 数组是切片和映射的基础数据结构。数组是值类型,在赋值和传递数组时将拷贝整个数组。
- 数组是一个长度固定的数据类型,存储着一段具有相同数据类型元素的连续内存块。
- 因为数组占用的内存是连续分配的,所以对数组元素的查询、修改等操作速度很快。
- 声明数组的方式:
- var array1 [5]int
- array1 := [5]int{3,5,6,3,2}
- array1 := [...]int{3,4,7,8,1} //根据数组字面量中元素的个数来确定数组的长度
- array1 := [5]int{0:3,3:5,4:8} //只初始化指定索引的元素,其余元素保持零值
- array1 := [...]int{1,2,9:32}
- 数组元素的类型可以为任何内置类型,也可以是某种结构类型,也可以是指针类型。
- 数组变量的类型包括数组长度和元素的类型,只有两部分都相同的数组才可相互赋值。
- 多维数组:数组本身只有一个维度,只能通过组合多个数组来创建多维数组;内置函数len、cap均返回第一维度的长度
- var array [4][2]int
- array := [4][2]int{2:{20,21},3:{41,25}}
- array := [4][2]int{2:{1:21},3:{0:41}}
- array := [...][4]int{{2,3},{4,5}} //仅第一维度允许使用“...”
- array[2][1] = 10
- 在函数间传递数组:由于在函数间传递变量时,传递的总是变量的值的副本,因为数组是值类型,所以在赋值和传递数组变量时将拷贝整个数组!在定义函数时,对于较大的数据类型应该把参数设计为指针类型,这样在调用函数时,只需在栈上分配给每个指针8字节的内存,但这意味着会改变指针指向的值(共享的内存),其实大部分情况下应该使用切片类型,而不是数组。
- 注意:因为切片的底层数组可能会在堆上分配内存,对于小数组在栈上拷贝的消耗可能比make代价小;
四、切片slice
- 切片slice是引用类型,它内部通过指针引用一个底层数组,并设定相关属性将数据的读写操作限定在指定区域。
- 创建和初始化:
- slice1 := make( []string, 5 ) //创建一个长度、容量都为5的string类型的切片
- slice1 := make( []string, 3, 5 ) //创建一个长度为3,容量为5的string类型的切片
- slice2 := []string{ "red","blue","green" } //长度和容量均为3的切片
- slice2 := []int{ 99:1 } //长度和容量均为100,并初始化第100个元素为1
- 再次切片reslice:以开始和结束原切片的索引位置确定所引用的数组片段,不支持反向索引,实际范围是一个右半开区间
假设原切片slice容量为k,新切片newSlice为原切片的索引 i 元素位置开始,在原切片的容量范围内取值
- newSlice := slice[ i : j ] //长度为j-i,容量为k-i
- newSlice := slice[ i : j : n ] //限制新切片的容量为n-i(第三个参数n-1表示新切片可扩展到的最后一个可见的底层数组部分的元素索引,这样就达到了限制容量的目的,注意:n必须>=j)
- 新切片无法访问它所指向的底层数组的第一个元素之前的部分(第一个索引之前的部分)
- 例子:ss:=[]int{10,20,30,40,50} newss:=ss[2:4:5] //newss为[30,40],容量为3
- 新切片和旧切片指向同一个底层数组;
//利用reslice实现一个栈式结构(也可将stack定义为一个类型)
var stack = make([]int,0,5)
func push(x int) error {
n:=len(stack)
if n == cap(stack) {
return errors.New("st |