陷阱:传递slice并尝试使用append来修改
实验与总结
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
// 1. append触发扩容底层数组改变,导致添加元素失败
handle(make([]int, 0, 0))
//调用函数前 Data:824634175272,Len:0,Cap:0
//函数内Append前 Data:824634175272,Len:0,Cap:0
//函数内Append后 Data:824633819240,Len:1,Cap:1
//调用函数后 Data:824634175272,Len:0,Cap:0
// 2. append未触发扩容,添加元素成功,但是len字段值未被修改
handle(make([]int, 0, 10))
//调用函数前 Data:824634175272,Len:0,Cap:10
//函数内Append前 Data:824634175272,Len:0,Cap:10
//函数内Append后 Data:824634175272,Len:1,Cap:10
//调用函数后 Data:824634175272,Len:0,Cap:10
// 3. 应该在append之后将值返回
var list = make([]int, 0)
list = goodHandle(list)
//调用函数前 Data:18533560,Len:0,Cap:0
//函数内Append前 Data:18533560,Len:0,Cap:0
//函数内Append后 Data:824633819368,Len:1,Cap:1
//调用函数后 Data:824633819368,Len:1,Cap:1
}
func goodHandle(list []int) []int {
var shStart = (*reflect.SliceHeader)(unsafe.Pointer(&list))
fmt.Printf("调用函数前 Data:%d,Len:%d,Cap:%d\n", shStart.Data, shStart.Len, shStart.Cap)
list = goodAppend(list)
var shEnd = (*reflect.SliceHeader)(unsafe.Pointer(&list))
reflect.ValueOf(list)
fmt.Printf("调用函数后 Data:%d,Len:%d,Cap:%d\n", shEnd.Data, shEnd.Len, shEnd.Cap)
fmt.Println()
return list
}
func goodAppend(v []int) []int {
var shStart = (*reflect.SliceHeader)(unsafe.Pointer(&v))
fmt.Printf("函数内Append前 Data:%d,Len:%d,Cap:%d\n", shStart.Data, shStart.Len, shStart.Cap)
v = append(v, 1024)
var shEnd = (*reflect.SliceHeader)(unsafe.Pointer(&v))
fmt.Printf("函数内Append后 Data:%d,Len:%d,Cap:%d\n", shEnd.Data, shEnd.Len, shEnd.Cap)
return v
}
// append触发扩容底层数组改变导致添加元素失效
func handle(list []int) {
var shStart = (*reflect.SliceHeader)(unsafe.Pointer(&list))
fmt.Printf("调用函数前 Data:%d,Len:%d,Cap:%d\n", shStart.Data, shStart.Len, shStart.Cap)
Append(list)
var shEnd = (*reflect.SliceHeader)(unsafe.Pointer(&list))
reflect.ValueOf(list)
fmt.Printf("调用函数后 Data:%d,Len:%d,Cap:%d\n", shEnd.Data, shEnd.Len, shEnd.Cap)
fmt.Println()
}
func Append(v []int) {
var shStart = (*reflect.SliceHeader)(unsafe.Pointer(&v))
fmt.Printf("函数内Append前 Data:%d,Len:%d,Cap:%d\n", shStart.Data, shStart.Len, shStart.Cap)
v = append(v, 1024)
var shEnd = (*reflect.SliceHeader)(unsafe.Pointer(&v))
fmt.Printf("函数内Append后 Data:%d,Len:%d,Cap:%d\n", shEnd.Data, shEnd.Len, shEnd.Cap)
}分析
思考
案例
reference
最后更新于