切片底层
1. 切片
切片,动态数组。
切片是Go中重要的数据类型,每个切片对象内部都维护着:数组指针、切片长度、切片容量 三个数据。
type slice struct {
array unsafe.Pointer
len int
cap int
在向切片中追加的数据个数大于容量时,内部会自动扩容且每次扩容都当前容量的2倍(当容量超过1024时每次扩容则只增加 1/4容量)。
1.1. 创建切片
// 创建切片
var nums []int
// 创建切片
var data = []int{11,22,33}
data:= []int{11,22,33}
// 创建切片
// make只用于 切片、字典、channel
var users = make([]int,1,3)
// 切片的指针类型
var v1 = new([]int)
// 指针类型(nil)
var v2 *[]int
1.2. 自动扩容
v1 := make([]int,1,3)
fmt.Println(len(v1),cap(v1))
// 其他
data := make([]int,3)
v1 := make([]int,1,3)
v2 := append(v1,66)
fmt.Println(v1) // [0 ]
fmt.Println(v2) // [0,66]
v1[0] = 999
fmt.Println(v1) // [999 ]
fmt.Println(v2) // [999,66]
// 需求:有一个切片,请往一个切片中追加一个数据。
v3 := make([]int,1,3)
v3 = append(v3,999)
v1 := []int{11,22,33}
v2 := append(v1,44)
v1[0] = 999
fmt.Println(v1) // [999 22 33]
fmt.Println(v2) // [11 22 33 44]
2. 常见操作
1 长度和容量
v1 := []int{11,22,33}
fmt.Println(len(v1), cap(v1))
2 索引
v1 := []string{"alex","李杰","老男孩"}
v1[0]
v1[1]
v1[2]
v2 := make([]int,2,5)
v2[0]
v2[1]
v2[2] // 报错
v2[0] = 999
3 切片
v1 := []int{11,22,33,44,55,66}
v2 := v1[1:3]
v3 := v1[1:]
v4 := v1[:3]
// 注意:通过切片切出来的数据和原切片内部存储的数据地址相同
4 追加
package main
import (
"fmt"
)
func main() {
v1 := []int{11,22,33}
v2 := append(v1,44)
v3 := append(v1,55,66,77,88)
v4 := append(v1, []int{100,200,300}...)
fmt.Println(v2)
fmt.Println(v3)
fmt.Println(v4)
}
>>> 输出
[11 22 33 44]
[11 22 33 55 66 77 88]
[11 22 33 100 200 300]
5 删除
package main
import "fmt"
func main() {
v1 := []int{11, 22, 33, 44, 55, 66}
deleteIndex := 2
// 切片获取到 {11,22,44、55、66}
// 又获取到 {44, 55, 66},将44、55、66要追加到
result := append(v1[:deleteIndex], v1[deleteIndex+1:]...)
fmt.Println(result) // [11 22 44 55 66]
fmt.Println(v1) //[11 22 44 55 66 66]
}
注意:使用切片时不太会使用删除。【链表】
6 插入
package main
import "fmt"
func main() {
v1 := []int{11, 22, 33, 44, 55, 66}
insertIndex := 3 // 在索引3的位置插入99
result := make([]int, 0, len(v1)+1)
result = append(result, v1[:insertIndex]...)
result = append(result,99)
result = append(result,v1[insertIndex:]...)
fmt.Println(result)
}
注意:效率低下。【链表】
7 循环
package main
import "fmt"
func main() {
v1 := []int{11, 22, 33, 99, 55, 66}
for i := 0; i < len(v1); i++ {
fmt.Println(i, v1[i])
}
for index, value := range v1 {
fmt.Println(index, value)
}
}
3. 切片嵌套
package main
import "fmt"
func main() {
v1 := []int{11, 22, 33, 99, 55, 66}
v2 := [][]int{[]int{11, 22, 33, 44}, []int{44, 55}}
v3 := [][2]int{[2]int{1, 2}, [2]int{4, 5}}
fmt.Println(v1)
fmt.Println(v2)
fmt.Println(v3)
v1[0] = 111111
v2[0][2] = 222222
v3[1][0] = 99999
fmt.Println(v1)
fmt.Println(v2)
fmt.Println(v3)
}
4. 变量赋值
整型
package main import "fmt" func main() { v1 := 1 v2 := v1 fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000b4008 fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000b4010 }
布尔类型
package main import "fmt" func main() { v1 := false v2 := v1 fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc00012a002 fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc00012a003 }
浮点型
package main import "fmt" func main() { v1 := 3.14 v2 := v1 fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc000016050 fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc000016058 }
字符串
package main import "fmt" func main() { v1 := "武沛齐" v2 := v1 fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc000010200 fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc000010210 }
注意:字符串内部元素不可被修改。
数组
package main import "fmt" func main() { v1 := [2]int{6, 9} v2 := v1 fmt.Println(v1, v2) fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000b4010 fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000b4020 v1[0] = 11111 fmt.Println(v1, v2) }
切片
package main import "fmt" func main() { v1 := []int{6, 9} v2 := v1 fmt.Println(v1, v2) // [6 9] [6 9] fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000a6020 fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000a6040 v1[0] = 11111 fmt.Println(v1, v2) // [11111 9] [11111 9] }
如果扩容,那么内部存储数据的数组就会重新开辟区域。
package main import "fmt" func main() { v1 := []int{6, 9} v2 := v1 fmt.Println(v1, v2) // [6 9] [6 9] fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000a6020 fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000a6040 v1 = append(v1, 999) fmt.Println(v1, v2) // [11111 9] [11111 9] }
总结,目前所学的所有的数据类型中,在修改切片的内部元素时,会造成所有的赋值的变量同时修改(不扩容)。
扩展:引用类型和值类型
。go
\
1: