【Go笔记】数组、切片和映射

3/10/2021 数组切片映射笔记

# 数组、切片和映射

介绍

数组类型的值(以下简称数组)的长度是固定的,而切片类型的值(以下简称切片)是可变长的。

# 数组

数组 类型名是 [n] emetType,其中n是数组长度,ementType 是数组元素类型 比如一个包 int 类型元素的数组类型可表示为 2[int] 。数组一般在创建时通过字面量初始化,单独声明一个数组类型变量而不进行初始化是没有意义的。

var arr[2] int  //声明一个有两个整型的数组,但元素默认值都是0,一般很少这样使用

array := [ ...]float64{7.0 , 8 . 5 , 9.1) //[...]后面跟字面量初始列表
1
2
3

数组初始化

a := [3]int{1,2,3} //指定长度和初始化字面量

a := [...]int{1,2,3} //不指定长度,但是由后面的初始化列表数量确定其长度

a := [3]int{1:1,2:3} //指定总长度,并通过索引值进行初始化,没有初始化元素时使用类型默认值

a := [...]int{1:1,2:3}//不指定总长度,通过索引值进行初始化,数组长度由最后一个索引值确定,没有指定索引的元素被初始化为类型的零值
1
2
3
4
5
6
7

数组的特点:

  1. 数组数组长度必须是常量,且是类型的组成部分。创建完长度就固定了,不可以再追加元素
  2. 数组是值类型的,数组复制或作为函数参数都是只拷贝
  3. 数组长度是数组类型的组成部分,[10]int 和 [20]int 表示不同的类型
  4. 可以根据数组创建切片
  5. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1
a := [...]int{1,2,3,4}
for i := 0; i < len(a); i++ {
}

for index, v := range a {
}
1
2
3
4
5
6
  1. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic
  2. 数组是值类型,赋值和传参会复制整个数组,而不是指针。因此改变副本的值,不会改变本身的值。
  3. 支持 “==”、"!=" 操作符,因为内存总是被初始化过的。
  4. 指针数组 [n]*T,数组指针 *[n]T。

# 数组相关操作

  1. 数组元素访问,例如:
a := [...]int{1,2,3}
b := a[0]
for i,v := range a{
....
}

1
2
3
4
5
6
  1. 数组长度,例如:
a := [...]int{1,2,3}
alengh := len(a)

for i:=0;i<len(a);i++{
...
}
1
2
3
4
5
6

# 切片

Go 语言的数组的定长性和值拷贝限制了其使用场景, Go 提供了另一种数据类型slice (中文为切片),这是一种变长数组,其数据结构中有指向数组的指针,所以是一种引用类型。例如:

//src/runtime/slice.go (go.19.1)
type slice struct{
    array unsafe.Pointer
    len int
    cap int
}
1
2
3
4
5
6

Go 为切片维护 三个元素一一指向底层数组的指针、切片的元素数量和底层数组的容量。具体结构如图:

image-20220216153656864

# 切片的创建.

# 由数组创建

当你事先知道数组中的值的时候,你可以使用这个方式。

创建语法如下 array[b:e] ,其中, array 表示数组名;b表示开始索引,可以不指定,默认是0; e表示结束索引 可以不指定,默认是 len(array)。 array[ b:e] 表示创建一个包含 e-b个元素的切片,第一个元素是 array[b] ,最后一个元素是 array[e-1] 。例如:

var array= [...]int{O,1,2,3,4,5,6) // 创建 int 型元素的数纽

s1 := array[0:4]
s2 := array[:4]
s3 := array[2:]

fmt Printf("%v\n",s1) // [0 1 2 3] 
fmt Printf("%v\n",s2) //[0 1 2 3] 
fmt Printf("%v\n",s3) //[2 3 4 5 6]
1
2
3
4
5
6
7
8
9

# 通过内置函数 make 创建切片

当你想要写入切片具体的索引时,第二个方法很有用

注意 make 创建的切片各元素被默认初始化为切片元素类型的零值。例如:

//len = 10,cap =10
a := make([]int,10)

//len =10,cap =15
b := make([]int,10,15)

fmt.Printf("%v\n",a) //结果为[ 0 0 0 0 0 0 0 0 O ]
fmt.Printf("%v\n",b) //结果为[ 0 0 0 0 0 0 0 0 O ]
1
2
3
4
5
6
7
8

⚠ 这里要注意:直接声明切片类型变量是没有意义的。例如:

var a []int
fmt.Printf("%v\n",b) //结果为[]
1
2

此时切片 的底层的数据结构如图 1-4 所示

image-20220216161012742

#

# 切片支持的操作

  • 内置函数len()返回切片长度
  • 内置函数cap()返回切片底层数组容量
  • 内置函数append()对切片追加元素
  • 内置函数copy()用于复制一个切片
    a := [...]int{0,1,2,3,4,5,6,7}
    b := make([]int,10)
    c := a[0:3]

    fmt.Println(len(b)) //10
    fmt.Println(cap(b)) //10

     b = append(b,2)
     fmt.Println(b) //[0 0 0 0 0 0 0 0 0 0 2]
     fmt.Println(len(b)) //11
     fmt.Println(cap(b)) //20

     d := make([]int,2,2)
     copy(d,c) //copy只会复制d 和 c 中长度最小的
     fmt.Println(d) //[0 1]
     fmt.Println(len(d)) //2
     fmt.Println(cap(d)) //2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 字符串和切片的相关转换

str := "hello,世界" //通过字符串字面量初始化一个字符串str
a := []byte(str) //将字符串转换为[]byte类型切片
b := []rune(str) //将字符串转换为[]rune类型切片
1
2
3

# 映射

Go 语言内置的字典类型 叫map。map 的类型格式是 p[K]T ,其中K可以是任意可以进行比较的类型, T是值类型。 map也是一种引用类型。

# map 的创建

  1. 使用字面量创建。
ma := map[string]int{"a":1,"b":2}
fmt.Println(ma["a"])
fmt.Println(ma["b"])
1
2
3
  1. 使用内置的make函数创建。
make(map[K]T) //map的容量使用默认值
make(map[K)T , len) //map的容量使用给定len值

mp1 := make(map[int]string)
mp2 := make(map[int]string,10)
map[1] = "tom"
mp2[1] = "pony"

fmt.Println(mpl[1]) //tom
fmt.Println(mp2[1]) //pony
1
2
3
4
5
6
7
8
9
10

# map 支持的操作

  • map的单个键值访问格式为 mapName[key], 更新某个 key 值时 mapName[key]放到等号左边,访问某个 key 的值时 mapName[key] 放在等号的右边。
  • 可以使用 range 遍历 map 类型变量,但是不保证每次选迭代元素的顺序。
  • 删除 map 中的某个键值,使用如下语法: delete(mapName,key) delete是内置函数,用来删除 map 中的某个键值对
  • 可以使用内置的 len() 函数返 map 中的键值对数量。例如:
map := make(map[int]string)
map[1] = "tom"
map[2] = "pony"

fmt.Println(map[1])
fmt.Println(len(map)) //len 函数返回map中的键值对数量

//range 支持遍历map,但不保证每次遍历次序是一样的
for k,v := range map {
    fmt.Println(k,v)
}
1
2
3
4
5
6
7
8
9
10
11

注意:

  • GO内置的map不是并发安全的,并发安全的map可以使用标准包sync中的map.
  • 不要直接修改map value 内某个元素的值,如果想修改map的某个键值,则必须整体赋值。例如:
type User struct {
    name string
    age int
}

map := make(map[int]User)

andes := User{
    name :"andes",
    age:18
}
map[1] = andes

ma[1].age = 19  //Error,不能通过map引用直接修改
andes.age = 19
map[1] = andes //必须整体替换value
fmt.Printf("%v\n",map)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Last Updated: 3/23/2022, 10:00:11 AM