目录
2. 直接创建 (直接创建切片, 会在内存中创建一个底层数组, 切片就是对底层数组的引用, 语法糖)
什么是切片
创建切片
1. 通过底层数组 (需要指定上界下界)
- 切片的上下界有默认值, 上界为0 , 下界为数组或切片的长度
package main
import (
"fmt"
)
func main() {
array := [5]int{1,2,3,4,5}
slice := array[1:4]
fmt.Printf("array值%v\n", array)
fmt.Printf("slice值%v\n", slice)
}
2. 直接创建 (直接创建切片, 会在内存中创建一个底层数组, 切片就是对底层数组的引用, 语法糖)
package main
import (
"fmt"
)
func main() {
slice := []int{1,2,3}
var slice2 []int = []int{1,2,3,4}
var slice3 = []int{1,2,3,4,5}
fmt.Printf("切片的值是 %v, 类型是 %T\n",slice, slice)
fmt.Printf("切片的值是 %v, 类型是 %T\n",slice2, slice2)
fmt.Printf("切片的值是 %v, 类型是 %T",slice3, slice3)
}
3. 通过make函数创建
package main
import (
"fmt"
)
func main() {
slice := make([]int, 5,5)
printSlice(slice)
for i,_ := range slice {
slice[i] = i
}
printSlice(slice)
}
func printSlice(slice []int) {
fmt.Println("切片的长度和容量分别是: ", len(slice), cap(slice), "值为", slice)
}
切片的长度和容量
package main
import (
"fmt"
)
func main() {
slice := []int{1,2,3,4,5,6,7,8,9}
printSlice(slice) // 长度9 容量9
slice2 := slice[:3] // === slice[0:3]
printSlice(slice2) // 长度3 容量9
slice3 := slice[1:6]
printSlice(slice3) // 长度5 容量8
}
func printSlice(slice []int) {
fmt.Println("切片的长度和容量分别是: ", len(slice), cap(slice))
}
切片默认值(零值)
package main
import (
"fmt"
)
func main() {
var slice []string // 声明未初始化 slice为零值nil
if (slice == nil) {
fmt.Println("slice = ", nil)
}
slice2 := []string{} // 空切片 != nil
if slice2 == nil {
fmt.Println("slice2 = ", nil)
}
if len(slice) == 0 && len(slice2) == 0 {
fmt.Println("slice2, slice 都是空切片 ")
}
}
append 给切片追加元素
官方例子:
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// 添加一个空切片
s = append(s, 0)
printSlice(s)
// 这个切片会按需增长
s = append(s, 1)
printSlice(s)
// 可以一次性添加多个元素
s = append(s, 2,3,4,5,6)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
其实前三行打印很好理解, 问题就在于第四行, 为什么我向切片中追加了7个元素, 而切片的容量却是8呢? 其实这是由于切片的扩容规则导致的, 下文会讲
切片的扩容规则
以下部分源码
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.cap < 1024 {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}
有些时候会遇到不符合上述的规则的情况, 这可能是由于类型导致的
package main
import "fmt"
func main() {
var s []int32
printSlice(s)
s = append(s, 0)
printSlice(s)
s = append(s, 1,2)
printSlice(s)
}
func printSlice(s []int32) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
package main
import "fmt"
func main() {
var s []int
printSlice(s)
s = append(s, 0)
printSlice(s)
s = append(s, 1,2)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
可以看到类型的不同确实对容量大小有影响
文章部分借鉴于 Go slice扩容深度分析 - 掘金本文主要是对go slice的扩容机制进行了一些分析。环境,64位centos的docker镜像+go1.12.1。 网上很多博客也有提到,slice扩容,cap不够1024的,直接翻倍;cap超过1024的,新cap变为老cap的1.25倍。 应该是4个8?基于翻倍的思路,c…https://juejin.cn/post/6844903812331732999