数组
初始化
数组可以保存指定长度的多个数据,且这些数据的类型都相同,数据类型可以是原始类型,如整型和字符串等,也可以是自定义类型。
001
在 Go 语言中声明数组的格式为:
1var variable [len]type
arr15int
1var arr1 [5]int
...
1var numArray = [...]int{1, 2, 3}
我们还可以根据索引来声明数组:
1a := [...]string{0: "北京", 1: "上海"} // 索引 0 对应的元素为"北京",1 对应的元素为"上海"
arriarr[i - 1]arr[len(arr) - 1]
arr[1] = 1
index out of range
遍历数组
1package main
2
3import "fmt"
4
5func main() {
6 a := [...]int{2, 4, 6, 8, 10}
7
8 for i := 0; i < len(a); i++ {
9 fmt.Println(a[i])
10 }
11}
1package main
2
3import "fmt"
4
5func main() {
6 a := [...]int{2, 4, 6, 8, 10}
7
8 for k, v := range a {
9 fmt.Println(k, v)
10 }
11}
切片
概念
slicepythonlist
切片是一个长度可变的数组。
cap()len()s
0 <= len(s) <= cap(s)
声明切片:
1var variable []type
可以通过类似数组的声明方式来声明切片:
1var s = []int{1, 2, 3}
arrs
1var arr = [...]int{1, 2, 3, 4, 5}
2var s []int = arr[0:3] // 声明切片 s,s 由 arr 中索引 0 到 2 的元素构成3var s1 []int = arr[:] // s1 由 arr 所有元素构成4var s2 []int = arr[2:] // s2 由 arr 中索引 2 开始到最后的元素构成5var s3 []int = arr[:3] // s3 由 arr 中索引 0 ~ 2 的元素构成
用 make() 创建切片
make()
1var s []type = make([]type, len)
typelen
我们来演示下切片的内存结构:
1package main
2
3import "fmt"
4
5func main() {
6 var slice1 []int = make([]int, 10)
7
8 for i := 0; i < len(slice1); i++ {
9 slice1[i] = 5 * i
10 }
11
12 for i := 0; i < len(slice1); i++ {
13 fmt.Printf("Slice at %d is %d\n", i, slice1[i])
14 }
15 fmt.Printf("\nThe length of slice1 is %d\n", len(slice1))
16 fmt.Printf("The capacity of slice1 is %d\n", cap(slice1))
17}
运行结果为:
1Slice at 0 is 0
2Slice at 1 is 5
3Slice at 2 is 10
4Slice at 3 is 15
5Slice at 4 is 20
6Slice at 5 is 25
7Slice at 6 is 30
8Slice at 7 is 35
9Slice at 8 is 40
10Slice at 9 is 45
11The length of slice1 is 10
12The capacity of slice1 is 10
我们可以在初始化切片时候,指定切片初始长度和切片容量:
1slice1 := make([]type, length, cap) // type 为类型,length 为初始长度, cap 为切片容量
切片重组
s11
1sl = sl[0 : len(sl)+1]
切片可以反复扩容直至切片长度到达切片容量:
1package main
2
3import "fmt"
4
5func main() {
6 slice1 := make([]int, 0, 10)
7 // load the slice, cap(slice1) is 10: 8 for i := 0; i < cap(slice1); i++ {
9 slice1 = slice1[0 : i+1]
10 slice1[i] = i
11 fmt.Printf("The length of slice is %d\n", len(slice1))
12 }
13
14 // print the slice:15 for i := 0; i < len(slice1); i++ {
16 fmt.Printf("Slice at %d is %d\n", i, slice1[i])
17 }
18}
上述代码运行结果为:
1The length of slice is 1
2The length of slice is 2
3The length of slice is 3
4The length of slice is 4
5The length of slice is 5
6The length of slice is 6
7The length of slice is 7
8The length of slice is 8
9The length of slice is 9
10The length of slice is 10
11Slice at 0 is 0
12Slice at 1 is 1
13Slice at 2 is 2
14Slice at 3 is 3
15Slice at 4 is 4
16Slice at 5 is 5
17Slice at 6 is 6
18Slice at 7 is 7
19Slice at 8 is 8
20Slice at 9 is 9
切片的复制与追加
copyappend
1package main
2
3import "fmt"
4
5func main() {
6 sl_from := []int{1, 2, 3}
7 sl_to := make([]int, 10)
8
9 n := copy(sl_to, sl_from)
10 fmt.Println(sl_to)
11 fmt.Printf("Copied %d elements\n", n) // n == 312
13 sl3 := []int{1, 2, 3}
14 sl3 = append(sl3, 4, 5, 6)
15 fmt.Println(sl3) // 1, 2, 3, 4, 5, 616}
appendappend
yxy..
1x = append(x, y...)
1func AppendByte(slice []byte, data ...byte) []byte {
2 m := len(slice) // 原切片长度 3 n := m + len(data) // 新切片长度 4 if n > cap(slice) { // 若新切片长度大于切片容量,手动扩容 5 newSlice := make([]byte, (n+1)*2)
6 copy(newSlice, slice)
7 slice = newSlice
8 }
9 // 复制元素10 slice = slice[0:n]
11 copy(slice[m:n], data)
12 return slice
13}
字符串、数组和切片的应用
从字符串生成字节切片
sc := []bytes(s)scopycopy (b []byte, s string)
截取字符串
substr := str[start:end]str start end-1
str[start:]startlen(str)-1
str[:end]end-1
字符串和切片的内存结构
字符串是一个双字结构,即一个指向实际数据的指针和记录字符串长度的整数,如下图所示:
修改字符串的字符
str[index]
1str[index] = 'A'
cannot assign to str[i]
因此,如果要修改字符串中的字符,需要先将字符串转换成字节数组,然后修改字节数组中的元素来实现修改字符串字符的目的,最后再将字节数组转换成字符串。例如:
1s := "hello"
2c := []byte(s)
3c[0] = 'm'
4s2 := string(c) // "mello"
append 函数
1b = make([]T, len(a))
2copy(b, a)
切片和垃圾回收
切片的底层指向一个数组,该数组的实际容量可能大于切片的长度。只有没有任何切片指向该数组时,底层数组才会被释放,这有可能会导致占用多余内存。
示例 :
FindDigits
1var digitRegexp = regexp.MustCompile("[0-9]+")
2
3func FindDigits(filename string) []byte {
4 b, _ := ioutil.ReadFile(filename)
5 return digitRegexp.Find(b)
6}
[]byte
1func FindDigits(filename string) []byte {
2 b, _ := ioutil.ReadFile(filename)
3 b = digitRegexp.Find(b)
4 c := make([]byte, len(b))
5 copy(c, b)
6 return c
7}