nil切片和空切片,切片深拷贝和浅拷贝


nil切片和空切片


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"fmt"
"reflect"
"unsafe"
)

func main() {

var s1 []int
s2 := make([]int, 0)
s4 := make([]int, 0)

fmt.Printf("s1 pointer:%+v, s2 pointer:%+v, s4 pointer:%+v, \n", *(*reflect.SliceHeader)(unsafe.Pointer(&s1)), *(*reflect.SliceHeader)(unsafe.Pointer(&s2)), *(*reflect.SliceHeader)(unsafe.Pointer(&s4)))

fmt.Printf("%v\n", (*(*reflect.SliceHeader)(unsafe.Pointer(&s1))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s2))).Data)
fmt.Printf("%v\n", (*(*reflect.SliceHeader)(unsafe.Pointer(&s2))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s4))).Data)
}

nil切片和空切片指向的地址不一样。nil空切片引用的数组 指针地址为0(没有指向任何实际地址)

空切片的引用数组指针地址是有的,且固定为一个值,即引用地址都是一样的。

输出:

1
2
3
4
s1 pointer:{Data:0 Len:0 Cap:0}, s2 pointer:{Data:1374390021784 Len:0 Cap:0}, s4 pointer:{Data:1374390021784 Len:0 Cap:0}, 
false
true


Json时的差异:

  • nil切片在JSON时会被编码成null

  • 空切片在JSON时会被编码成[]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"encoding/json"
"fmt"
)

func main() {

type Person struct {
Ages []int `json:"ages"`
}

var s1 []int
s2 := make([]int, 0)

json1, _ := json.Marshal(Person{s1})
json2, _ := json.Marshal(Person{s2})

fmt.Printf("%s\n", string(json1))
fmt.Printf("%s\n", string(json2))

}

输出:

1
2
{"ages":null}
{"ages":[]}

Golang: Nil vs Empty Slice (零值切片和空切片的坑)


深拷贝和浅拷贝



浅拷贝(也称为位拷贝)就是拷贝指向对象的指针,即拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间 (改其中一个会影响到另外一个)。浅拷贝只是一种简单的拷贝,让几个对象共用一个内存。 浅拷贝可能会有数据安全方面的隐患
深拷贝则是另辟了一个完全独立的内存空间,源对象与拷贝对象互相独立,改其中一个不会影响
另外一个。但需为新的变量 重新分配一块内存

值类型与引用类型-值传递与引用传递-浅拷贝与深拷贝

Go中切片之间的浅拷贝和深拷贝

在 Go 中,一个数组拥有其元素,但一个切片只是引用着其元素。

在 Go 中,值的复制都是浅拷贝,复制一个值不会复制它所引用的值。所以复制一个切片不会复制其元素。

这可以反映在下面的程序中,该程序打印出 189

1
2
3
4
5
6
7
8
9
10
11
12
package main

func main() {
var s = []int{1, 2, 3}

for i, n := range s {
if i == 0 {
s[1], s[2] = 8, 9
}
print(n)
}
}


深拷贝的情况:

不同写法的性能差异-byte切片转string string(byteSli)的方式是深拷贝,为新生成的新字符串新分配了一块内存

golang之slice中的小tips-使用copy(深度)拷贝切片