day05 切片slice

切片

什么是切片

  • 切片长度不固定,不设定长度
  • 内置数据类型
  • 三元素:
    • 指针 slice 指定的开始位置
    • 长度 slice 的长度
    • 容量 slice 开始到最后的最大长度
package main

import "fmt"

func main() {
	/*
		切片特点:
			- 切片长度不固定,不设定长度
			- 内置数据类型
			- 三元素:
				- 指针 slice 指定的开始位置
				- 长度 slice 的长度
				- 容量 slice 开始到最后的最大长度
	*/
	// 定义切片
	slice01 := []int{} //
	fmt.Printf("%T\n", slice01)
	fmt.Println("默认切片:", slice01)
	fmt.Println("切片长度:", len(slice01))
	fmt.Println("切片容量:", cap(slice01))

	// 定义空切片 slice02 == nil
	var slice02 []int
	if slice02 == nil {
		fmt.Println(slice02 == nil)
		fmt.Println("切片空", slice02)
	}

	// 初始化切片
	slice03 := []int{1, 2, 3, 4}
	fmt.Println("slice03有值切片:", slice03)
	fmt.Printf("%T\n", slice03)
	fmt.Println("slice03切片长度:", len(slice03))
	fmt.Println("slice03切片容量:", cap(slice03))
}

make 定义切片

  • make 函数 ----> 创建切片
package main

import "fmt"

func main() {
	// make 函数 ----> 创建切片

	slice004 := make([]int, 5, 10)
	fmt.Printf("slice004切片数据:%T\n", slice004)
	fmt.Printf("slice004切片长度:%d\n", len(slice004))
	fmt.Printf("slice004切片容量:%d\n", cap(slice004))

	// 容量为5 能放6个数据吗? 【不能,超出容量】
	//slice004[6] = 1
	//fmt.Println(slice004) //  index out of range [6] with length 5

	// 切片如何扩容. append
	slice004 = append(slice004, 7, 1)
	fmt.Println(slice004)

	// 容量也会扩容. 遵循二倍扩容:1.当前容量两扩大1倍数.
	slice004 = append(slice004, 7, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6)
	slice004 = append(slice004, 7, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6)
	fmt.Println("扩容后的slice004:", slice004)
	fmt.Printf("扩容后slice004切片数据:%T\n", slice004)
	fmt.Printf("扩容后slice004切片长度:%d\n", len(slice004))
	fmt.Printf("扩容后slice004切片容量:%d\n", cap(slice004))
}

切片追加

package main

import "fmt"

func main() {

	// 切片追加:  ...切片 表示拆解切片内的元素
	slice05 := make([]int, 0, 3)
	slice06 := []int{1, 2, 3, 4, 5, 6}

	// 将 slice06 追加到 slice05 中
	// slice06... 。即: 将slice06 进行了结构操作,循环 slice06中的每一个元素
	slice05 = append(slice05, slice06...)
	fmt.Println("slice05:", slice05)

}

遍历切片

package main

import "fmt"

func main() {
	// 遍历切片
	ergodicSlice1 := []int{1, 2, 3, 4}
	for i := 0; i < len(ergodicSlice1); i++ {
		fmt.Println(ergodicSlice1[i])
	}

	ergodicSlice2 := []int{1, 2, 3, 4}
	for index, sliceVal := range ergodicSlice2 {
		fmt.Println(index, sliceVal)
	}
}

切片内存分析

  • 切片 容量扩充/扩容内存 分析
  • cap 成倍增加。容量超过1024,则按照1.2倍数增长
  • 容量增加,内存地址就会发生变化
package main

import "fmt"

func main() {

	// 切片 容量扩充/扩容内存 分析
	// cap 成倍增加。容量超过1024,则按照1.2倍数增长
	// 容量增加,内存地址就会发生变化
	sliceMemory := []int{1, 2, 3}
	fmt.Printf("切片长度:%d 切片容量:%d\n", len(sliceMemory), cap(sliceMemory))
	fmt.Printf("切片地址:%p\n", sliceMemory)
	sliceMemory = append(sliceMemory, 1, 2)
	fmt.Printf("切片长度:%d 切片容量:%d\n", len(sliceMemory), cap(sliceMemory))
	fmt.Printf("切片地址:%p\n", sliceMemory)
	sliceMemory = append(sliceMemory, 2, 3)
	fmt.Printf("切片长度:%d 切片容量:%d\n", len(sliceMemory), cap(sliceMemory))
	fmt.Printf("切片地址:%p\n", sliceMemory)

	/*
		总结:
			- 1. 每一个切片,底层是数组
			- 2. 切片本身不存储数据,而是通过底层数组存储数据。修改切片的容量,也就修改数组中的数据,内存地址发生变化
			- 3. append 追加数据/切片扩容时。只要容量够用,指向同一个【内存地址的数组】
			- 4. 数组属于值类型copy
	*/
}

切片扩容

package main

import "fmt"

func main() {
	// 通过使用 copy 函数 实现切片make扩容,copy实现原数据到新切片

	sliceCopyBefore := []int{1, 2, 3}
	fmt.Printf("原切片。长度:%d, 容量:%d\n", len(sliceCopyBefore), cap(sliceCopyBefore))
	fmt.Printf("原切片内存地址:%p\n", sliceCopyBefore)
	// 1. make 扩容 新切片
	sliceCopyAfter := make([]int, cap(sliceCopyBefore)*2)

	// 2. 通过 copy 将 原切片内的数组中数据拷贝到新的切片数组中的数据
	copy(sliceCopyAfter, sliceCopyBefore)
	fmt.Printf("新切片。长度:%d, 容量:%d\n", len(sliceCopyAfter), cap(sliceCopyAfter))
	fmt.Printf("新切片内存地址:%p\n", sliceCopyAfter)

}

数组的切片

package main

import "fmt"

func main() {
	// 数组:连续的内存地址
	// 切片底层指向一个数组
	arraySlice := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	arraySlice01 := arraySlice[0:3] // 指向同一个地址 。 内存地址:0xc000026140
	arraySlice02 := arraySlice[:5]  // 指向同一个地址 。 内存地址:0xc000026140
	arraySlice03 := arraySlice[2:5] // 内存地址发生变化
	arraySlice04 := arraySlice[6:]  // 内存地址发生变化
	arraySlice05 := arraySlice[:10] // 指向同一个地址 。 内存地址:0xc000026140

	/*
		结果:
			- 1. 使用 [start:end] 对数组进行切片
			- 2. 起始位置从头开始,则使用同一块数组内存地址。
			- 3. 从中间位置开始 切。 容量会切到最后。eg [2:5],容量为8,长度为3
			- 4. 数组, 使用 [start:end] 结果会变成 切片类型
			- 5. 容量不变。修改数组和切片。指向同一个数据。
			- 6. 容量扩容。切片地址发生内存变化
	*/
	fmt.Printf("arraySlice01 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice01), cap(arraySlice01), arraySlice01, arraySlice01)
	fmt.Printf("arraySlice02 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice02), cap(arraySlice02), arraySlice02, arraySlice02)
	fmt.Printf("arraySlice03 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice03), cap(arraySlice03), arraySlice03, arraySlice03)
	fmt.Printf("arraySlice04 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice04), cap(arraySlice04), arraySlice04, arraySlice04)
	fmt.Printf("arraySlice04 最新截断的第一个元素的内存地址:%p\n", arraySlice04)
	fmt.Printf("arraySlice 第6个元素的内存地址:%p\n", &arraySlice[6])
	fmt.Printf("arraySlice05 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice05), cap(arraySlice05), arraySlice05, arraySlice05)
	fmt.Printf("arraySlice05 数组第一个元素 内存地址:%p\n", arraySlice05)

}

切片的类型

package main

import "fmt"

func main() {
	// 数组 是值类型
	array1 := [3]int{1, 2, 3}
	array2 := array1
	array1[2] = 100
	// 深拷贝。指向不同的内存地址
	fmt.Printf("array1:%v,array2:%v\n", array1, array2) // array1:[1 2 100],array2:[1 2 3]

	// 切片 是引用类型
	// 浅拷贝,指向同一个内存地址
	s1 := []int{1, 2, 3}
	s2 := s1
	s2[1] = 200
	fmt.Printf("s1:%v,s2:%v\n", s1, s2) // s1:[1 200 3],s2:[1 200 3]

}

切片如何实现深拷贝

  • 使用make开辟新的切片
  • 使用copy函数实现 切片深拷贝
package main

import "fmt"

func main() {
	/*
		// 切片如何实现 深拷贝
		- 1. 使用make开辟新的切片
		- 2. 使用copy函数实现 切片深拷贝
	*/
	s3 := []int{1, 2, 3, 4, 5}
	s4 := make([]int, 0)
	for _, i := range s3 {
		s4 = append(s4, i)
	}
	// 修改s4
	s4[3] = 100
	fmt.Printf("s3:%p,s4:%p\n", s3, s4) // s3:0xc000024210,s4:0xc0000221c0
	fmt.Printf("s3:%v,s4:%v\n", s3, s4) // s3:[1 2 3 4 5],s4:[1 2 3 100 5]

	// 空类型 切片拷贝:copy 不会以追加方式拷贝,而是以相同位置替换。
	// s3中的函数 拷贝到 s5  : 【 dst, src 】
	s5 := []int{1, 1, 1, 1, 1, 1, 1, 1, 1}
	copy(s5, s3)
	fmt.Printf("s3:%p,s5:%p\n", s3, s5) // s3:0xc0000b8000,s5:0x1d97300
	fmt.Printf("s3:%v,s5:%v\n", s3, s5)

	// s6中的函数 拷贝到 s3  : 【 dst, src 】
	// 空类型 切片拷贝:copy 不会以追加方式拷贝,而是以相同位置替换。
	s6 := []int{1, 1, 1, 1, 1, 1, 1, 1, 1}
	copy(s3, s6)
	fmt.Printf("s3:%p,s6:%p\n", s3, s6) // s3:0xc000024210,s6:0xc000026140
	fmt.Printf("s3:%v,s6:%v\n", s3, s6) // s3:[1 1 1 1 1],s6:[1 1 1 1 1 1 1 1 1]

}

数组和切片作为函数的参数

package main

import "fmt"

func updateSlice(s []int) {
	fmt.Println("函数接收切片的值:", s)
	s[2] = 100
	fmt.Println("函数修改切片的值:", s)

}
func updateArray(a [3]int) {
	fmt.Println("函数接收数组的值:", a)
	a[2] = 100
	fmt.Println("函数修改数组的值:", a)
}

func main() {
	a1 := [3]int{1, 2, 3}
	s1 := []int{1, 2, 3}
	fmt.Println("切片传入函数前的值:", s1)
	updateSlice(s1)
	fmt.Println("切片传入函数后的值:", s1)
	fmt.Println("-----------")
	fmt.Println("数组传入函数前的值:", a1)
	updateArray(a1)
	fmt.Println("数组传入函数后的值:", a1)

}
posted @ 2024-07-02 00:36  染指未来  阅读(2)  评论(0编辑  收藏  举报