关于golang:The-Way-To-Go-切片

40次阅读

共计 2301 个字符,预计需要花费 6 分钟才能阅读完成。

初识切片

根本应用

在 go 语言中个别不应用数组,大多都是应用切片(slice),看一个切片的示例


arr := [...]int{0,1,2,3,4,5,6,7,8}

s := arr[2:6]

这里定的 s 就是切片,上边的 arr 是一个数组,这里 s 的后果是[2,3,4,5](取 arr 中 3 到 5 这个区间的数据,是左闭右开的)

切片还有很多的用法,如下:


arr := [...]int{0,1,2,3,4,5,6,7,8}

fmt.Println("arr[2:6] =", arr[2:6])

fmt.Println("arr[:6] =", arr[:6])

fmt.Println("arr[2:] =", arr[2:6])

fmt.Println("arr[:] =", arr[:])

输入后果:


arr[2:6] = [2 3 4 5]

arr[:6] = [0 1 2 3 4 5]

arr[2:] = [2 3 4 5]

arr[:] = [0 1 2 3 4 5 6 7 8]

像这种方括号中 ([]) 加个冒号 (:) 的数据结构,都能够看做是 切片(slice)。当然还有很多其它的申明办法

切片是对数组的 view

咱们晓得在 go 中,数组是一个 值类型 ,而切片是一个 援用类型 ,切片是对数组的 视图(view),可能不太好了解,看下边的代码


func updateSlice(s []int) {s[0] = 520

}

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

s1 := arr[2:]

fmt.Println("s1 更新之前")

fmt.Println("s1 =", s1)

fmt.Println("arr =", arr)

fmt.Println("更新切片 s1")

updateSlice(s1)

fmt.Println("更新之后,s1 和 arr 的值")

fmt.Println(s1)

fmt.Println(arr)

}

输入后果:


s1 更新之前

s1 = [2 3 4 5 6 7 8]

arr = [0 1 2 3 4 5 6 7 8]

更新切片 s1

更新之后,s1 和 arr 的值

[520 3 4 5 6 7 8]

[0 1 520 3 4 5 6 7 8]

因为 s1(切片)是对 arr(数组)的视图(view),所以当 s1 中的值被扭转之后,数组中的值也产生了扭转(扭转的是 s1 中下标为 0 的元素,对应的是数组 arr 中下标为 2 的元素)

对切片进行切片操作


func learnSlice1() {arr := [...]int{0,1,2,3,4,5,6,7,8}

s1 := arr[2:6]

s2 := s1[1:]

fmt.Println("s1 =", s1)

fmt.Println("s2 =", s2)

}

输入后果:


s1 = [2 3 4 5]

s2 = [3 4 5]

s2 是对切片 s1 又进行了一次切片

深度了解切片

间接看一个示例


func learnSlice2() {arr := [...]int{0,1,2,3,4,5,6,7,8}

s1 := arr[2:6]

s2 := s1[3:5]

fmt.Println("s1 =", s1)

fmt.Println("s2 =", s2)

}

s1 的打印后果,咱们必定晓得,然而这里的 s2 打印后果是什么?

咱们晓得 s1 = [2,3,4,5],s2 是对 s1 取下标是 3 到 5 这个区间的数据,也就是 s1[3]、s1[4]。然而能够看到 s1 的下标最大是 s[3],那这里 s1[3:5]会报错吗?

答案是不会报错,能够看一下打印的后果,而后再解释为什么


s1 = [2 3 4 5]

s2 = [5 6] //s1[3]、s1[4]

能够看到 s2 中的那个 6 就不在 s1 里边,如果咱们尝试间接打印 s1[4]会报错。然而打印 s2 这个切片,就会失常打印出后果,那到底这个 6 是如何取出来的?

上边有说切片 (slice) 是对数组 (array) 的视图(view),那这个底层是什么样的,如何 view 的?

上边给出的根底数组 arr 是 [0,1,2,3,4,5,6,7,8],而后 s1 := arr[2:6],取到的就是[2,3,4,5],这四个数字映射到 s1 的下标就是 0、1、2、3,s1 里边因为是对底层数组 arr 的 view,它的下标不是到 3 就完结了,它还有 4、5 的,然而间接通过 s1[4] 或 s1[5]是取不到的,然而 s1 还是晓得它里边有 4 和 5 这两个下标的,因为 s1 是晓得底层的数组的

而后,s2 := s1[3:5],取到的就是 s1 中 3,4 这两个下标的值。s2 的下标就是 0、1、2(2 其实是看不见的)。从底层数组的角度 s1[3]、s1[4]的值就是 5 和 6

切片外部实现

切片中首先有一个 ptr 指针,它指向 slice 开始的那个元素。有一个 len,标记的是切片的长度,咱们应用下标的形式对切片取值的时候,最大只能取到下标为 len- 1 的值,如果大于或等于 len,就会报错。而后它里边还有一个值 cap,它代表的是整个数组从 ptr 指向的地位开始到完结的长度

切片它能够向后扩大,然而不能够向后扩大。比方 s1:=arr[2:6],s1 最前边只能看到 2,前边的 0、1 下标对应的值是看不到的

切片的下标不能够超过 len(s),向后扩大不能够超过底层数组 cap(s)

看一波示例


func learnSlice2() {arr := [...]int{0,1,2,3,4,5,6,7,8}

s1 := arr[2:6]

s2 := s1[3:5]

fmt.Printf("s1 = %v, len(s1) = %d, cap(s1) = %d", s1, len(s1), cap(s1))

fmt.Println()

fmt.Printf("s2 = %v, len(s2) = %d, cap(s2) = %d", s2, len(s2), cap(s2))

}

输入后果


s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 7

s2 = [5 6], len(s2) = 2, cap(s2) = 4

正文完
 0