引出
因为数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性。 例如:
func arraySum(x [3]int) int{
sum := 0
for _, v := range x{
sum = sum + v
}
return sum
}
这个求和函数只能接受[3]int类型,其他的都不支持。 再比如,
a := [3]int{1, 2, 3}
切片的本质
- 切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。
- 切片的本质:切片就是一个框,框住了一块连续的内存。
- 切片属于引用类型,真正的数据都是保存再底层数据组里的
切片的基本定义与类型1
切片基本要素
// 切片指向了一个底层的数组。
// 切片的长度就是它元素的个数。
// 切片的容量是底层数组从切片的第一个元素到最后一个元素的数量。
切片的定义
var name []T
- name:表示变量名
- T:表示切片中的元素类型
//切片的定义
var s1 []int // 定义一个存放int类型元素的切片
var s2 []string // 定义一个存放string类型元素的切片
fmt.Println(s1, s2)
fmt.Println(s1 == nil) //nil:为空
fmt.Println(s2 == nil)
初始化
//初始化
s1 = []int{1, 2, 3}
s2 = []string{"Adminxe", "Azjj", "化鱼"}
fmt.Println(s1, s2)
fmt.Println(s1 == nil)
fmt.Println(s2 == nil)
长度和容量
// 切片的长度就是它元素的个数。
// 切片的容量是底层数组从切片的第一个元素到最后一个元素的数量。
fmt.Printf("len(s1):%d cap(s1):%d\n", len(s1), cap(s1)) //len:长度
fmt.Printf("len(s2):%d cap(s2):%d\n", len(s2), cap(s2)) //cap:容量
由数组得到切片
//2.由数组得到切片
a1 := [...]int{1, 3, 5, 7, 9, 11, 13}
s3 := a1[0:4] // 0:4 ==> 0、1、2 基于一个数组的切割,左包含右不包含(左开右闭)
fmt.Println(s3)
s4 := a1[1:6]
fmt.Println(s4)
s5 := a1[:4] //开始到4 ==> [0:4]
s6 := a1[3:] //3到结束 ==> [3:len(a1)] [7, 9, 11, 13]
s7 := a1[:] //开始到结束==> [0:len(a1)]
fmt.Println(s5, s6, s7)
//切片的容量是指底层数组的容量
fmt.Printf("len(s5):%d cap(s5):%d\n", len(s5), cap(s5))
//底层数组从切片的第一个元素到最后的元素数量
fmt.Printf("len(s6):%d cap(s6):%d\n", len(s6), cap(s6))
切片再切割
//3.切片再切割
s8 := s6[3:] //[1]
fmt.Printf("len(s8):%d cap(s8):%d\n", len(s8), cap(s8))
//切片是引用类型,都指向了底层的一个数组。
fmt.Println("s6:", s6)
a1[6] = 1300 //修改了底层数组的值
fmt.Println("s6:", s6)
fmt.Println("s8:", s8)
}
笔记练习代码1
package main
import "fmt"
// 切片指向了一个底层的数组。
// 切片的长度就是它元素的个数。
// 切片的容量是底层数组从切片的第一个元素到最后一个元素的数量。
func main() {
//切片的定义
var s1 []int // 定义一个存放int类型元素的切片
var s2 []string // 定义一个存放string类型元素的切片
fmt.Println(s1, s2)
fmt.Println(s1 == nil) //nil:为空
fmt.Println(s2 == nil)
//初始化
s1 = []int{1, 2, 3}
s2 = []string{"Adminxe", "Azjj", "化鱼"}
fmt.Println(s1, s2)
fmt.Println(s1 == nil)
fmt.Println(s2 == nil)
//长度和容量
fmt.Printf("len(s1):%d cap(s1):%d\n", len(s1), cap(s1)) //len:长度
fmt.Printf("len(s2):%d cap(s2):%d\n", len(s2), cap(s2)) //cap:容量
//2.由数组得到切片
a1 := [...]int{1, 3, 5, 7, 9, 11, 13}
s3 := a1[0:4] // 0:4 ==> 0、1、2 基于一个数组的切割,左包含右不包含(左开右闭)
fmt.Println(s3)
s4 := a1[1:6]
fmt.Println(s4)
s5 := a1[:4] //开始到4 ==> [0:4]
s6 := a1[3:] //3到结束 ==> [3:len(a1)] [7, 9, 11, 13]
s7 := a1[:] //开始到结束==> [0:len(a1)]
fmt.Println(s5, s6, s7)
//切片的容量是指底层数组的容量
fmt.Printf("len(s5):%d cap(s5):%d\n", len(s5), cap(s5))
//底层数组从切片的第一个元素到最后的元素数量
fmt.Printf("len(s6):%d cap(s6):%d\n", len(s6), cap(s6))
//3.切片再切割
s8 := s6[3:] //[1]
fmt.Printf("len(s8):%d cap(s8):%d\n", len(s8), cap(s8))
//切片是引用类型,都指向了底层的一个数组。
fmt.Println("s6:", s6)
a1[6] = 1300 //修改了底层数组的值
fmt.Println("s6:", s6)
fmt.Println("s8:", s8)
}
切片的基本定义与类型2
make()函数创造切片
s1 := make([]int, 5, 10) // (类型,长度,容量(容量要是不写则延续长度))
fmt.Printf("s1=%v len(s1)-%d cap(s1)-%d\n", s1, len(s1), cap(s1))
s2 := make([]int, 0, 10) // (类型,长度,容量)
fmt.Printf("s2=%v len(s2)-%d cap(s2)-%d\n", s2, len(s2), cap(s2))
判断切片是否为空
//要检查切片是否为空,使用len(s) == 0来判断,不能使用s == nil来判断。
切片不能直接比较
//片之间是不能比较的,我们不能使用==操作符来判断两个切片是否含有全部相等元素。
// 切片唯一合法的比较操作是和nil比较。
// 一个nil值的切片并没有底层数组,一个nil值的切片的长度和容量都是0。
//但是我们不能说一个长度和容量都是0的切片一定是nil
var s11 []int //len(s1)=0;cap(s1)=0;s1==nil
s22 := []int{} //len(s2)=0;cap(s2)=0;s2!=nil
s33 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
切片的赋值拷贝
s3 := []int{1, 3, 5}
s4 := s3
s3[0] = 1000
fmt.Println(s3, s4)
切片的遍历
//1.索引遍历
for i := 0; i < len(s3); i++ {
fmt.Println(s3[i])
}
//2.for range循环
for i, v := range s3 {
fmt.Println(i, v)
}
}
笔记练习代码2
package main
//切片的本质:切片就是一个框,框住了一块连续的内存。
//切片属于引用类型,真正的数据都是保存再底层数据组里的
import "fmt"
//make()函数创造切片
func main() {
s1 := make([]int, 5, 10) // (类型,长度,容量(容量要是不写则延续长度))
fmt.Printf("s1=%v len(s1)-%d cap(s1)-%d\n", s1, len(s1), cap(s1))
s2 := make([]int, 0, 10) // (类型,长度,容量)
fmt.Printf("s2=%v len(s2)-%d cap(s2)-%d\n", s2, len(s2), cap(s2))
//要检查切片是否为空,使用len(s) == 0来判断,不能使用s == nil来判断。
//切片不能直接比较
//片之间是不能比较的,我们不能使用==操作符来判断两个切片是否含有全部相等元素。
// 切片唯一合法的比较操作是和nil比较。
// 一个nil值的切片并没有底层数组,一个nil值的切片的长度和容量都是0。
//但是我们不能说一个长度和容量都是0的切片一定是nil
var s11 []int //len(s1)=0;cap(s1)=0;s1==nil
s22 := []int{} //len(s2)=0;cap(s2)=0;s2!=nil
s33 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
fmt.Printf("len(s11):%d cap(s11):%d\n", len(s11), cap(s11))
fmt.Printf("len(s22):%d cap(s22):%d\n", len(s22), cap(s22))
fmt.Printf("len(s33):%d cap(s33):%d\n", len(s33), cap(s33))
//切片的赋值拷贝
s3 := []int{1, 3, 5}
s4 := s3
s3[0] = 1000
fmt.Println(s3, s4)
//切片的遍历
//1.索引遍历
for i := 0; i < len(s3); i++ {
fmt.Println(s3[i])
}
//2.for range循环
for i, v := range s3 {
fmt.Println(i, v)
}
}
append()方法为切片追加元素
package main
import "fmt"
//append()为切片追加元素
func main() {
s1 := []string{"Adminxe", "Azjj", "化鱼"}
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
// s1[3] = "广州" //错误的写法 会导致编译错误:索引越界
// fmt.Println(s1)
//调用append函数必须用原来的切片变量来接收返回值
s1 = append(s1, "MoCo") //当append追加元素,原来的底层数组放不下的时候,Go底层就会把底层数组换一个
//如果源切片容量够,就修改底层数组;若容量不够则开辟新的内存空间,不影响数组
//append相当于新建了一个数组,然后对原数组进行赋值操作
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
s1 = append(s1, "海底", "哦哦哦") // 必须用变量接收append的返回值
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
ss := []string{"瓜皮辰", "Corl7", "Fengxin"}
s1 = append(s1, ss...) // ...表示拆开
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
}
Copy()函数复制切片
package main
import "fmt"
func main() {
a1 := []int{1, 3, 5}
a2 := a1 //赋值
var a3 = make([]int, 3, 3)
copy(a3, a1) // copy copy从新开辟了一片空间,等同于建立副本
fmt.Println(a1, a2, a3)
a1[0] = 100
fmt.Println(a1, a2, a3)
}
从切片中删除元素
package main
import "fmt"
func main() {
a1 := []int{1, 3, 5}
//从切片中删除元素
//将a1中的索引为1的3这个元素删掉
a1 = append(a1[:1], a1[2:]...)
fmt.Println(a1)
fmt.Println(cap(a1))
fmt.Println(a1)
//将a1中的索引为1的3这个元素删掉专项解释
x1 := [...]int{1, 3, 5} //数组
s1 := x1[:] //切片
fmt.Println(s1, len(s1), cap(s1))
//1.切片不保存具体的值
//2.切片对应一个底层数组
//3.底层数组都是占用一块连续的内存
fmt.Printf("%p\n", &s1[0]) //%p:内存地址
s1 = append(s1[:1], s1[2:]...) //修改了底层数组
fmt.Printf("%p\n", &s1[0])
fmt.Println(s1, len(s1), cap(s1))
//?
s1[0] = 100 //修改底层数组
fmt.Println(x1) // [1 5 5]
}
参考链接
https://www.liwenzhou.com/posts/Go/06_slice/
转载请注明:Adminxe's Blog » Go语言学习–切片(slice)