Go语言笔记--切片

1.说明

1)其本身并不是数组,它指向底层的数组

2)作为变长数组的替代方案,可以关联底层数组的局部或全部

3)为引用类型

4)可以直接创建或从底层数组获取生成

5)使用len()获取元素个数,cap()获取容量

6)一般使用make()创建

7)如果多个slice指向相同底层数组,其中一个的值改变会影响全部

8)切片本身没有数据,是对数组底层的一个view

 

2.创建:

make([]T, len, cap)

其中cap可以省略,则容量和len的值相同

len表示存数的元素个数,cap表示容量

代码实例:直接var s []int形式

package main


import "fmt"


func main() {
    var s []int //没有元素则切片是空的
    for i := 0; i < 100; i++ {
        s = append(s, i)
    }
    fmt.Println(s)
}
输出:
API server listening at: 127.0.0.1:33537
[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99]

使用make创建:

package main


import "fmt"


func main() {
    s := make([]int, 10)
    for i := 0; i < 10; i++ {
        s[i] = i
    }
    fmt.Println(s)
}
输出:
API server listening at: 127.0.0.1:21778
[0 1 2 3 4 5 6 7 8 9]

 

3.方法

1)Reslice

Reslice时所有以呗slice的切片为准

所有不可以超过呗slice的切片的容量cap()值

索引越界不会导致底层数组的重新分配而是引发错误

2)Append

可以在slice尾部追加元素

可以将一个slice追加在另一个slice尾部

如果最终长度为超过主机到slice的容量则返回原始slice

如果超过追加道德slice 的容量则将重新分配数组并拷贝原始数据

3)Copy

4.代码实例

package main


import "fmt"


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


输出:
API server listening at: 127.0.0.1:37693
arr[2:6]: [2 3 4 5]
arr[:6]: [0 1 2 3 4 5]
arr[2:]: [2 3 4 5 6 7 8 9]
arr[:]: [0 1 2 3 4 5 6 7 8 9]

上述代码中:

arr[2:6]从数组中取值是第2号元素到第5号元素,不包括6号

arr[:6]从头到第5号元素,不包括6号

arr[2:]从2号元素到结尾,包括2号元素

arr[:]获取所有元素

实例二

package main


import "fmt"


//参数中数组不加长度,这个就是切片
func updateSlice(s []int) {
    s[0] = 999
}


func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    s1 := arr[2:]
    fmt.Println("s1:", s1)
    s2 := arr[:]
    fmt.Println("s2:", s2)
    fmt.Println("after updateSlice(s1)")
    updateSlice(s1)
    fmt.Println(s1)
    fmt.Println(arr)


    fmt.Println("after updateSlice(s2)")
    updateSlice(s2)
    fmt.Println(s2)
    fmt.Println(arr)
}

API server listening at: 127.0.0.1:19977
s1: [2 3 4 5 6 7 8 9]
s2: [0 1 2 3 4 5 6 7 8 9]
after updateSlice(s1)
[999 3 4 5 6 7 8 9]
[0 1 999 3 4 5 6 7 8 9]
after updateSlice(s2)
[999 1 999 3 4 5 6 7 8 9]
[999 1 999 3 4 5 6 7 8 9]

这段代码中updateSlice完成了对数组的数据更新

切片还有一种操作叫做reslice

package main


import "fmt"


func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    s := arr[:]
    fmt.Println(s)
    s = s[:5]
    fmt.Println(s)
    s = s[2:]
    fmt.Println(s)
}
输出:
API server listening at: 127.0.0.1:3798
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4]
[2 3 4]

5.扩展

1)实例说明

看下面一段代码执行结果是多少:

package main


import "fmt"


func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    s1 := arr[2:6
    fmt.Println(s1)
    s2 := s1[3:5]
    fmt.Println(s2)
}

输出:
API server listening at: 127.0.0.1:43832
[2 3 4 5]
[5 6]

上述代码S的值是2,3,4,5但是s2是s1的切片,为什么取值不是s1里面的内容呢,显然5和6已经超出了范围。请看下图:

有底层数组向上一次是数组arr的内容是0,1,2,3,4,5,6,7那么s1作为arr的切片取值下标是2--6也就是说:

s1[0] = 2

s1[1] = 3

s1[2] = 4

s1[3] = 5

s1[4] = 6

s1[5] = 7

s2是s1的切片,取值是s1的3--5下标,对应到数组arr里面就是arr[5]--arr[6]两个元素

所以s2的元素值就是:

s2[0] = 5

s2[1] = 6

s2[2] = 7

2)底层实现

如下图所示slice内部三个元素

切片扩展有两个规则:

1)slice可以向后扩展,不可以向前扩展

2)s[i]不可以超越len(s),向后扩展不可以超越底层数组cap(s)

package main


import "fmt"


func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    s1 := arr[2:6]
    fmt.Println(s1)
    fmt.Println(len(s1))
    fmt.Println(cap(s1))
    s2 := s1[3:5]
    fmt.Println(s2)
    fmt.Println(len(s2))
    fmt.Println(cap(s2))
}

输出:
API server listening at: 127.0.0.1:21562
[2 3 4 5]
4
6
[5 6]
2
3

6.向切片增加元素

规则:

1)添加元素时如果超越cap,系统会重新分配更大的底层数组

2)由于值传递的关系,必须接收append的返回值(原因就是因为可能超越cap,这时分配的是新的底层数组)

看下面一段代码,通过append向切片内部增加元素

package main


import "fmt"


func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    s1 := arr[2:6]
    fmt.Println("s1 = ", s1)
    s2 := s1[3:5]
    fmt.Println("s2 = ", s2)
    s3 := append(s2, 10)
    s4 := append(s3, 11)
    s5 := append(s4, 12)
    fmt.Println("s3, s4, s5 = ", s3, s4, s5)
    fmt.Println("arr = ", arr)
}
输出:
API server listening at: 127.0.0.1:18118
s1 =  [2 3 4 5]
s2 =  [5 6]
s3, s4, s5 =  [5 6 10] [5 6 10 11] [5 6 10 11 12]
arr =  [0 1 2 3 4 5 6 10]

上述代码显示s4和s5已经超越了arr所以这哥底层数组已经不是之前的arr了是一个新的arr

下面代码通过打印len和cap观察切片的长度和容量是如何扩展增加的,cap是倍数扩展的

package main


import "fmt"


func printSlice(s []int) {
    fmt.Println("len(s) =  cap(s) = ", len(s), cap(s))
}


func main() {
    var s []int //没有元素则切片是空的,不会崩溃
    for i := 0; i < 10; i++ {
        printSlice(s)
        s = append(s, i)
    }
    fmt.Println(s)
}

输出:
API server listening at: 127.0.0.1:25704
len(s) =  cap(s) =  0 0
len(s) =  cap(s) =  1 1
len(s) =  cap(s) =  2 2
len(s) =  cap(s) =  3 4
len(s) =  cap(s) =  4 4
len(s) =  cap(s) =  5 8
len(s) =  cap(s) =  6 8
len(s) =  cap(s) =  7 8
len(s) =  cap(s) =  8 8
len(s) =  cap(s) =  9 16
[0 1 2 3 4 5 6 7 8 9]

7.拷贝删除操作

package main


import "fmt"


func main() {
    s1 := []int{2, 4, 6, 8}
    fmt.Println("s1 = ", s1)
    s2 := make([]int, 16)
    fmt.Println("s2 = ", s2)
    copy(s2, s1) //拷贝s1到s2
    fmt.Println("s2 = ", s2)
    s2 = append(s2[:3], s2[4:]...) //删除8
    fmt.Println("s2 = ", s2)       //打印出来可以看到8这个元素被删除了整个切片的长度小了一个
    //删除头元素操作
    front := s2[0] //取出来查看头元素
    s2 = s2[1:]    //删除头元素
    fmt.Println("front = ", front)
    fmt.Println("s2 = ", s2)
    //删除尾元素操作
    tail := s2[len(s2)-1] //取出来查看尾元素
    s2 = s2[:len(s2)-1]   //删除尾元素
    fmt.Println("tail = ", tail)
    fmt.Println("s2 = ", s2)
}
输出:
API server listening at: 127.0.0.1:47314
s1 =  [2 4 6 8]
s2 =  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
s2 =  [2 4 6 8 0 0 0 0 0 0 0 0 0 0 0 0]
s2 =  [2 4 6 0 0 0 0 0 0 0 0 0 0 0 0]
front =  2
s2 =  [4 6 0 0 0 0 0 0 0 0 0 0 0 0]
tail =  0
s2 =  [4 6 0 0 0 0 0 0 0 0 0 0 0]

练习实例:

    s1 := []int{2, 4, 6, 8} //初始化
	fmt.Println("s1 = ", s1)
	s2 := make([]int, 16) //申请一个空的,默认初始化值都是0
	fmt.Println("s2 = ", s2)
	copy(s2, s1) //拷贝s1到s2
	fmt.Println("s2 = ", s2)
	s2 = append(s2[:3], s2[4:]...) //删除8
	fmt.Println("s2 = ", s2)       //打印出来可以看到8这个元素被删除了整个切片的长度小了一个
	//删除头元素操作
	front := s2[0] //取出来查看头元素
	s2 = s2[1:]    //删除头元素
	fmt.Println("front = ", front)
	fmt.Println("s2 = ", s2)
	//删除尾元素操作
	tail := s2[len(s2)-1] //取出来查看尾元素
	s2 = s2[:len(s2)-1]   //删除尾元素
	fmt.Println("tail = ", tail)
	fmt.Println("s2 = ", s2)

输出:

s1 =  [2 4 6 8]
s2 =  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
s2 =  [2 4 6 8 0 0 0 0 0 0 0 0 0 0 0 0]
s2 =  [2 4 6 0 0 0 0 0 0 0 0 0 0 0 0]
front =  2
s2 =  [4 6 0 0 0 0 0 0 0 0 0 0 0 0]
tail =  0
s2 =  [4 6 0 0 0 0 0 0 0 0 0 0 0]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值