Go的切片(slice)

发布于 2023-10-10  143 次阅读


[top]

目标:什么是Golang的切片

什么是切片

在 Go 语言中,切片(slice)是一种动态数组,可以根据需要动态地增长或缩小。切片底层是一个数组,但与数组不同的是,切片的长度是可以动态改变的。

切片初始化

 // 切片初始化的三种方式
package main

import "fmt"
func main() {
	// 1.make方法
	var makeSlice = make([]string, 3)
	makeSlice := make([]string, 3) // 也可以简写为
	fmt.Println(makeSlice)

	// 2.从数组直接创建
	arr := [5]string{"go", "gin", "grpc", "mysql", "elasticsearch"}
	arrToSlice := arr[0:len(arr)]
	fmt.Println(arrToSlice)

	// 3.使用string{}
	stringToSlice := []string{"go", "gin", "grpc"}
	fmt.Println(stringToSlice)
}

Go的切片在函数传递的时候是值传递还是引用传递?

严格来讲是值传递,但是效果呈现出来是引用传递(不完全)

我们可以同一个例子得出结论:值传递

 // 案例
package main

import (
	"fmt"
	"strconv"
)

func printSlice(data []string) {
	data[0] = "java" // 方法内修改会影响传入的data

        // 但是方法内的append却不会影响到传入的data
	for i := 0; i < 10; i++ {
		data = append(data, strconv.Itoa(i))
	}
}

func main() {
	courses := []string{"go", "grpc", "gin"}
	printSlice(courses) // 执行方法
	fmt.Println(courses) // 结果 [java grpc gin]
}

切片的原理

示例1

在 Go 中,函数参数传递都是值传递。但对于引用类型,传递的值实际上是指向底层数据结构的指针,因此在函数内部对其进行的修改会影响到原始数据。

 // 案例
package main

import (
	"fmt"
	"strconv"
)

func main() {
	data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	s1 := data[1:6] // s1当前:[2, 3, 4, 5, 6]
	s2 := data[2:7] // s2当前:[3, 4, 5, 6, 7]
	s2[0] = 22 // 修改s2的第0个数据
	fmt.Println(s1) // s1结果:[2 22 4 5 6]
	fmt.Println(s2) // s2的结果: [22 4 5 6 7]
        fmt.Println(data) // data的结果:[1 2 22 4 5 6 7 8 9 10]
}
ç

示例1图解

切片是底层数组的一种引用形式,它们通过指向数组并确定段的起始和终止来确定如何访问数据。

多个切片可以引用同一个底层数组的不同部分,它们可能会或不会重叠。

对底层数组的修改将通过所有切片进行反映,这些切片引用了数组的被修改的部分。

示例2

在扩容前的s3[0] = 33是会影响到data/s1/s2,但是扩容(扩容:是成倍扩容)后修改的就是一个全新的数据了。

 // 案例
package main

import (
	"fmt"
	"strconv"
)

func main() {
	data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	s1 := data[1:6] // s1当前:[2, 3, 4, 5, 6]
	s2 := data[2:7] // s2当前:[3, 4, 5, 6, 7]
	s2[0] = 22 // 修改s2的第0个数据
	fmt.Println(s1) // s1结果:[2 22 4 5 6]
	fmt.Println(s2) // s2的结果: [22 4 5 6 7]
        fmt.Println(data) // data的结果:[1 2 22 4 5 6 7 8 9 10]

        // 在示例1基础上新增的
        s3 := data[3:8]
	s3[0] = 33
	s3 = append(s3, 1, 2, 3, 4, 5, 6, 7, 8) // append超过cap上限,这个操作是为了造成扩容
	s3[1] = 44
	fmt.Println(s1) // s1:[2 22 33 5 6]
	fmt.Println(s2) // s2:[22 33 5 6 7]
	fmt.Println(s3) // s3:[33 44 6 7 8 1 2 3 4 5 6 7 8]
}

示例2图解


扩容

  1. 如果当前的切片容量小于 1024,那么新的容量通常是当前容量的2倍。(即:新容量 = 2倍的当前容量)
  2. 如果当前的切片容量大于等于 1024,新的容量增加为原来容量的 1.25,增加25%(即:新容量 = 当前容量 + 当前容量/4)。

间歇性凌云壮志,持续性混吃等死