13、切片

1.切片的定义

Go 语言切片是对数组的抽象
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增
切片是一种方便、灵活且强大的包装器。切片本身没有任何数据。它们只是对现有数组的引用。
切片与数组相比,不需要设定长度,在口中不用设定值,相对来说比较自由
从概念上面来说slice像一个结构体,这个结构体包含了三个元素:

  • 1.指针,指向数组中slice指定的开始位置
  • 2.长度,即slice的长度
  • 3.最大长度,也就是slice开始位置到数组的最后位置的长度

2.语法格式

var variable_name [] variable_type

可以发现切片和数组的语法格式很想,但是不需要指定大小的,也可以称之为:动态数组
例如:

var s1 []int
fmt.Println(s1)

s2 := []int{1, 2, 3, 4}
fmt.Println(s2)
fmt.Printf("s1的类型:%T", s1)

3.使用make(t Type,size ...IntegerType) Type内置函数创建切片

/**
	使用make内置函数
	- 第一个参数:类型
		- slice
		- map
		- chan
	- 第二个参数:长度len
		- 实际存储的元素
	- 第三个参数:容量cap
		能够存储的最多元素数量
	*/
	s3 := make([]int, 0, 5)
	fmt.Println(s3)

4.append内置函数操作切片中的元素

// 使用append内置函数向切片末尾添加元素
	s3 = append(s3, 1, 2, 3)
	fmt.Println(s3)
	// fmt.Println(s3[4]) // index out of range [4] with length 3

	/**
	超过容量了也没事,会自动扩容
		扩容后会改变底层数组的引用地址
	*/
	s3 = append(s3, 4, 5, 6)
	fmt.Println(s3)
	fmt.Println("扩容", len(s3))

	// 也可以把另外一个切append到当前切片
	s3 = append(s3, s2...)
	fmt.Println(s3)

5.数组的扩容机制

切片Slice:

  • 1.每一个切片引用了一个底层数组
  • 2.切片本身不存储任何数据,都是这个底层数组存储,所以修改切片也就是修改这个数组中的数据
  • 3.当向切片中添加数据时,如果没有超过容量,直接添加,如果超过容量,自动扩容(成倍增长)
  • 4.切片一旦扩容,就是重新指向一个新的底层数组
s1 := []int{1, 2, 3}
fmt.Println(s1)
fmt.Printf("len:%d,cap:%d\n", len(s1), cap(s1))
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", &s1)

s1 = append(s1, 4, 5)
fmt.Println(s1)
fmt.Printf("len:%d,cap:%d\n", len(s1), cap(s1))
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", &s1)

s1 = append(s1, 6, 7, 8)
fmt.Println(s1)
fmt.Printf("len:%d,cap:%d\n", len(s1), cap(s1))
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", &s1)

s1 = append(s1, 9, 10)
fmt.Println(s1)
fmt.Printf("len:%d,cap:%d\n", len(s1), cap(s1))
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", &s1)

6.在已有的数组上创建切片

slice := arr[start:end]

  • 切片中的数据:[start,end)
  • arr[:end],从头到end
  • arr[start:]从start到未尾

从已有的数组上,直接创建切片,该切片的底层数组就是当前的数组.

  • 长度是从start到end切割的数据量。
  • 但是容量从start到数组的末尾。
/**
 * @author ly (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2023/4/3  20:56
 * @tags 喜欢就去努力的争取
 */
package main

import "fmt"

func main() {
	a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(a)

	s1 := a[:5]
	s2 := a[3:8]
	s3 := a[5:]
	s4 := a[:]
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(s3)
	fmt.Println(s4)

	// 输出长度和容量
	fmt.Printf("s1 len:%d,cap:%d\n", len(s1), cap(s1))
	fmt.Printf("s2 len:%d,cap:%d\n", len(s2), cap(s2))
	fmt.Printf("s3 len:%d,cap:%d\n", len(s3), cap(s3))
	fmt.Printf("s4 len:%d,cap:%d\n", len(s4), cap(s4))

	// 打印内存地址
	fmt.Printf("%p\n", s1)
	fmt.Printf("%p\n", s2)
	fmt.Printf("%p\n", s3)
	fmt.Printf("%p\n", s4)

	// 更改数组内容,响应的切片内容也会随之更改
	a[4] = 1000
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(s3)
	fmt.Println(s4)

	// 更改切片内容,数组的内容也会随之更改
	s3[3] = 888
	fmt.Println(a)
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(s3)
	fmt.Println(s4)

	// 向切片中添加内容
	s2 = append(s2, 111, 222, 333)
	fmt.Println(a)
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(s3)
	fmt.Println(s4)

}

7.切片是引用数据类型

按照类型来分:

  • 基本类型:int,float,string,bool
  • 复合类型: array,slice,map,struct,pointer, function,chan

按照特点来分:

  • 值类型: int,float,string,bool,array传递的是数据副本
  • 引用类型: Slice传递的地址,多个变量指向了同一块内存地址

所以: 切片是引用类型的数据,存储了底层数组的引用

/**
 * @author ly (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2023/4/3  21:45
 * @tags 喜欢就去努力的争取
 */
package main

import "fmt"

func main() {

	// 数组:值类型
	arr1 := [2]int{1, 2}
	arr2 := arr1
	fmt.Println("数组改变前:", "arr1", arr1, "arr2", arr2)

	arr1[0] = 5
	fmt.Println("数组改变后:", "arr1", arr1, "arr2", arr2)

	// 切片:引用类型
	s1 := []int{10, 20, 30}
	s2 := s1
	fmt.Println("切片改变前:", "s1", s1, "s2", s2)
	s1[0] = 100

	fmt.Println("切片改变后:", "s1", s1, "s2", s2)

	// 打印内存地址
	fmt.Printf("%p\n", &arr1)
	fmt.Printf("%p\n", &arr2)
	fmt.Printf("%p\n", s1) // 底层数组的内存地址
	fmt.Printf("%p\n", s2)
	fmt.Printf("%p\n", &s1) // 打印切片本身的内存地址
	fmt.Printf("%p\n", &s2)

}

image

image

posted @   我也有梦想呀  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示