切片Slice
Go语言切片是对数组的抽象
Go数组的长度不可改变,在特定场景这样的集合就不太适用,Go提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大
切片是一种方便、灵活且强大的包装器,切片本身没有任何数据,他们只是对现有数组的引用
切片与数组相比,不需要设定长度,在[]中不用设定值,相对来说比较自由
从概念上面来说slice像一个结构体,这个结构体包括三个元素:
- 指针:指向数组中slice指定的开始位置
- 长度:即slice的长度
- 最大长度:也就是slice开始位置到数组最后位置的长度
定义切片
package main
import "fmt"
func main() {
// 数组长度一旦确定就不可改变
arr := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr)
// 定义切片
var s1 []int
fmt.Println(s1)
if s1 == nil {
fmt.Println("切片为空")
}
s2 := []int{1, 2, 3} //切片 变长
fmt.Println(s2)
fmt.Printf("%T%T\t%T", s1, s2, arr)
}
/*
结果:
[1 2 3 4 5]
[]
切片为空
[1 2 3]
[]int[]int [5]int
*/
make函数创建切片
使用make()函数来创建切片
make([]T,length,capactity)
切片是可索引的,并且可以由len()方法来获取长度
切片提供了计算容量的方法cap()可以测量切片最长可以到达多少
package main
import "fmt"
func main() {
// 用make函数创建切片
s1 := make([]int, 5, 10)
fmt.Println(s1)
fmt.Println(len(s1)) //长度:5
fmt.Println(cap(s1)) //容量:10
s1[0] = 100 //给元素进行赋值
//s1[6] = 20 //index out of range [6] with length 5
fmt.Println(s1)
}
/*
[0 0 0 0 0]
5
10
[100 0 0 0 0]
*/
切片扩容和遍历
package main
import "fmt"
func main() {
s1 := make([]int, 0, 5)
s1 = append(s1, 1, 2, 3)
fmt.Println(s1)
//如果切片中的数据超过了规定的容量,那么他就会自动扩容
s1 = append(s1, 4, 5, 6, 7, 8, 9)
fmt.Println(s1)
s2 := []int{1, 1, 1, 1, 1}
s1 = append(s1, s2...) //将s2的数据添加到s1里面 s2...可以理解为结构体 目的将s2里面的数据解析出来
fmt.Println(s1)
//循环遍历输出切片的数据
for i := 0; i < len(s1); i++ {
fmt.Println(s1[i])
}
//range遍历
for _, i := range s1 { //_,i 将打印下标去掉 只打印输出值
fmt.Println(i)
}
}
/*
[1 2 3]
[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9 1 1 1 1 1]
1
2
3
4
5
6
7
8
9
1
1
1
1
1
1
2
3
4
5
6
7
8
9
1
1
1
1
1
*/
扩容的内存分析
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3}
fmt.Println(s1)
fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(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)
s1 = append(s1, 6, 7)
fmt.Println(s1)
fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
fmt.Printf("地址:%p\n", s1)
s1 = append(s1, 8, 9, 10)
fmt.Println(s1)
fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
fmt.Printf("地址:%p\n", s1)
}
/*
[1 2 3]
长度len:3,容量cap:3
地址:0xc0000aa078
[1 2 3 4 5]
长度len:5,容量cap:6
地址:0xc0000c8030
[1 2 3 4 5 6 7]
长度len:7,容量cap:12
地址:0xc000086060
[1 2 3 4 5 6 7 8 9 10]
长度len:10,容量cap:12
地址:0xc000086060
*/
- 每一个切片引用了一个底层数组
- 切片本身不存储任何数据,都是这个底层数组存储,所以修改切片也就是修改这个数组的数据
- 当向切片中添加数据时,如果没有超过容量,直接添加,若果超过容量,自动扩容,成倍增加
- 切片一旦扩容,就会重新指向一个新的底层数组
在已有数组上创建切片
从已有的数组上,直接创建切片,该切片的底层数组就是当前的数组,长度是从start到end切到的数据量,但是容量从start到数组的末尾
slice := arr[start:end]
package main
import "fmt"
func main() {
//定义一个数组
arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
s1 := arr[:5] //切片从1-5 [1 2 3 4 5]
s2 := arr[4:8] //[5 6 7 8]
s3 := arr[5:] //[6 7 8 9 10]
s4 := arr[:] //[1 2 3 4 5 6 7 8 9 10]
fmt.Println(s1)
fmt.Println(s2)
fmt.Println(s3)
fmt.Println(s4)
fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
fmt.Printf("长度len:%d,容量cap:%d\n", len(s2), cap(s2))
fmt.Printf("长度len:%d,容量cap:%d\n", len(s3), cap(s3))
fmt.Printf("长度len:%d,容量cap:%d\n", len(s4), cap(s4))
arr[0] = 100 //将数组元素值进行更换
fmt.Println(arr)
fmt.Println(s1)
s1[1] = 100
fmt.Println(arr)
fmt.Println(s1)
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", &arr)
}
/*
[1 2 3 4 5]
[5 6 7 8]
[6 7 8 9 10]
[1 2 3 4 5 6 7 8 9 10]
长度len:5,容量cap:10
长度len:4,容量cap:6
长度len:5,容量cap:5
长度len:10,容量cap:10
[100 2 3 4 5 6 7 8 9 10]
[100 2 3 4 5]
[100 100 3 4 5 6 7 8 9 10]
[100 100 3 4 5]
0xc0000ac0f0
0xc0000ac0f0
*/
切片是引用类型
package main
import "fmt"
func main() {
//数组:值传递
arr1 := [4]int{1, 2, 3, 4}
arr2 := arr1
arr2[0] = 100
fmt.Println(arr1, arr2)
//切片:引用类型
s1 := []int{1, 2, 3, 4}
s2 := s1
//切片2里元素发生变化,切片1也会跟随着变化
s2[0] = 200
fmt.Println(s1, s2)
//说明切片的copy指向的是地址
fmt.Printf("%p,%p", s1, s2)
}
/*
[1 2 3 4] [100 2 3 4]
[200 2 3 4] [200 2 3 4]
0xc000012260,0xc000012260
*/
深拷贝与浅拷贝
深拷贝:拷贝的是数据本身
- 值类型的数据,默认都是深拷贝: array、int、float、string.bool、sturct
- 浅拷贝:拷贝的是数据的地址,会导致多个变量指向同一块内存
- 引用类型的数据,默认都是浅拷贝: slice、map
- 因为切片是引用类型的数据,直接拷贝的是地址
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3, 4}
s2 := make([]int, 0, 0)
for i := 0; i < len(s1); i++ {
s2 = append(s2, s1[i]) //将s1里的元素一个一个追加到s2里面
}
fmt.Println(s1)
fmt.Println(s2)
//切片深拷贝
s2[0] = 100
fmt.Println(s1)
fmt.Println(s2)
fmt.Printf("%p,%p", s1, s2)
// copy
s3 := []int{5, 6, 7, 8}
fmt.Println(s1, s3)
copy(s1, s3) //(接收者,传递者)
fmt.Println(s1, s3)
fmt.Printf("%p,%p", s1, s3)
}
标签:Map,s1,cap,len,切片,Println,Go,fmt
From: https://www.cnblogs.com/DuPengBG/p/16992070.html