第21节 go 语言切片原理

❤️💕💕Go语言高级篇章,在此之前建议您先了解基础和进阶篇。Myblog:http://nsddd.topopen in new window

Go语言基础篇open in new window

Go语言100篇进阶open in new window


[TOC]

代码~

💡简单的一个案例如下:

// 切片原理
package main

import "fmt"

func main() {
	s := []int{1, 2, 3, 4, 5, 6}
	fmt.Println("s is array:", s)
	s1 := s[0:3]
	fmt.Println("s1 is slice:", s1)
	s2 := s[3:6]
	fmt.Println("s2 is slice:", s2)

	//s1和s2共享底层数组
	_ = append(s1, 7)
	fmt.Println("s2 checkout is slice:", s2)
}

提示

按理说,按理说,应该是 append 影响的是 s1 ,与我 s2 有何关系❓

所以打印的是:[4,5,6] 那么你就失望了

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\86-main.go"
s is array: [1 2 3 4 5 6]
s1 is slice: [1 2 3]
s2 is slice: [4 5 6]
s2 checkout is slice: [7 5 6]

原因

则需要我们理解 slice 的底层原理和机制了, slice 说是切片, 但是实际上是一个 映射

从一个大的 slice 中映射下来,形成一个新的 slice.

测试

💡简单的一个案例如下:

// Slice principle
package main

import "fmt"

func main() {
	s := []int{1, 2, 3, 4, 5, 6}
	fmt.Println("s is array:", s)
	s1 := s[0:3]
	fmt.Println("s1 is slice:", s1)
	s2 := s[3:6]
	fmt.Println("s2 is slice:", s2)

	//S1 and s2 share the underlying array
	_ = append(s1, 7)
	fmt.Println("s1 checkout is slice:", s1)
	fmt.Println("s2 checkout is slice:", s2)

	//Print s again
	fmt.Println("s is array:", s)

	//Cut again
	s3 := s1[0:2]
	fmt.Println("s3 is slice:", s3)

	//Add 8 to s3
	s3 = append(s3, 8)
	fmt.Println("s3 checkout is slice:", s3)

	//Print s1
	fmt.Println("s1 checkout is slice:", s1)

	//Print s2
	fmt.Println("s2 checkout is slice:", s2)

	//Print s again
	fmt.Println("s is array:", s)
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\86-main.go"
s is array: [1 2 3 4 5 6]
s1 is slice: [1 2 3]
s2 is slice: [4 5 6]
s1 checkout is slice: [1 2 3]
s2 checkout is slice: [7 5 6]
s is array: [1 2 3 7 5 6]
s3 is slice: [1 2]
s3 checkout is slice: [1 2 8]
s1 checkout is slice: [1 2 8]
s2 checkout is slice: [7 5 6]
s is array: [1 2 8 7 5 6]

不改变 s2

如果希望不影响 s2 ,我们可以使用 s1 = append([]int{}, s1...) 强迫 go 分配新的空间

💡简单的一个案例如下:

// Slice principle
package main

import "fmt"

func main() {
	s := []int{1, 2, 3, 4, 5, 6}
	fmt.Println("s is array:", s)
	s1 := s[0:3]
	fmt.Println("s1 is slice:", s1)
	s2 := s[3:6]
	fmt.Println("s2 is slice:", s2)

	//S1 and s2 share the underlying array
	s1 = append([]int{}, s1...)
	fmt.Println("s1 checkout is slice:", s1)
	fmt.Println("s2 checkout is slice:", s2)
	fmt.Println("s is array:", s)
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\87-main.go"
s is array: [1 2 3 4 5 6]
s1 is slice: [1 2 3]
s2 is slice: [4 5 6]
s1 checkout is slice: [1 2 3]
s2 checkout is slice: [4 5 6]
s is array: [1 2 3 4 5 6]

总结

📜 对上面的解释

我们可以看到有几个很重要的细节,依次展开:

  1. appent 如果不接收那么是临时的,也就是说 _ = append(s1, 7) 并不会影响 s1
  2. appent 如果接收那么是永久的,也就是说 s1 = append(s1, 7) 会影响 s1,还有 s2
  3. 切片是映射 , append 本质上是修改和替换
  4. 如果希望不影响 s2 ,我们可以使用 s1 = append([]int{}, s1...) 强迫 go 分配新的空间

警告

掌握原理很重要,不要觉得 go 语言简单,简单你咋还在吹水。

kubernetes 源码看了嘛, API Server 的实现了解嘛,docker 的网络实现了解嘛…….

END 链接