type slice struct {
array unsafe.Pointer //指向底层数组的指针
len int //切片中元素个数
cap int //切片总容量
}
golang 源码
基于数组或者slice生成一个slice的时候,新的slice和原来数组/slice 的底层数组是同一个
基于数组或者slice生成slice的cap=原来对应的数组长度-现在slice的第一个元素对应的索引
slice 作为参数传递的是 副本,但是对应的数组的指针不变
package main
import "fmt"
var arr = []int{1,2,3,4,5}
func testSliceAsParam1(s1 []int) {
s1[0] = 5 //扩容前修改,影响传入slice,因为s1指向底层数组没变,但是底层数组元素值变了
return
}
func testSliceAsParam2(s1 []int) {
s1 = append(s1, 6) //扩容后修改,不影响传入slice,因为扩容后产生了新的底层数组,函数体内的
//副本s1,其指向底层数组的指针已经改变,指向新生成的底层数组,此时修改只
//是修改新的底层数组,原s1指向的底层数组元素值没变
s1[0] = 9
return
}
func main() {
s1 := arr[:5]
fmt.Println("before1: ")
fmt.Println(s1)// [1 2 3 4 5]
testSliceAsParam1(s1)
fmt.Println("after1: ")
fmt.Println(s1)// [5 2 3 4 5]
testSliceAsParam2(s1)
fmt.Println("after2: ")
fmt.Println(s1) //[5 2 3 4 5]
}
确切地说,一个切片的底层数组永远不会被替换。为什么?虽然在扩容的时候 Go 语言一定会生成新的底层数组,但是它也同时生成了新的切片。它是把新的切片作为了新底层数组的窗口,而没有对原切片及其底层数组做任何改动。
测试:
append扩容后,确实产生了新的底层数组,也生成了新的切片;但当你用原切片作为append的接收者,因为‘=’是值传递,你看到切片的地址是没有改变的。
package main
import "fmt"
var arr = []int{1,2,3,4,5}
func main() {
s1 := arr[:5]
fmt.Printf("%p", &s1) //0xc0420023e0
fmt.Println()
s2 := append(s1, 6) //确实产生了新的底层数组和新的切片
fmt.Printf("%p", &s2) //0xc042002420
fmt.Println()
s1 = s2 //值传递,这里等价于s1 = append(s1,6)
fmt.Printf("%p", &s1) //0xc0420023e0
}
package main
import "fmt"
var arr = []int{1,2,3,4,5,6,7,8,9}
func main() {
s1 := append(arr[:2], arr[3:]...)
fmt.Println(s1) //[1 2 4 5 6 7 8 9]
fmt.Println(arr) //[1 2 4 5 6 7 8 9 9] 有大量元素移动
}
type student struct {
Name string
Age int
}
func pase_student1() {
m := make(map[string]*student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for _, stu := range stus {
//stu是副本,&stu是一个定值,
//而里边存的东西会变,
//最终存储切片最后一个值
m[stu.Name] = &stu
}
for k, v := range m {
fmt.Println(k, v)
}
}
func pase_student2() {
m := make(map[string]student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for _, stu := range stus {
m[stu.Name] = stu
}
for k, v := range m {
fmt.Println(k, v)
}
}
func main() {
pase_student1()
pase_student2()
}
转载slice删除元素的性能对比