1.new() 与 make() 的区别
new对于简单的类型和数组,比如int ,char,数组的初始化,不仅会初始化出指针,由于内部构造单一,所以内部也帮忙构造出来【自己的目前的猜想】new函数去初始化,主要是为类型申请一片内存空间,返回执行内存的指针slice、map、chan初始化后还是不能使用,会触发panic,这是因为new对于这三种结构只能做到给整体一个地址,至于地址里面的构造是不会帮忙初始化出来的,因为new自己不知道给slice、map、channel多大的长度【自己的目前的猜想】make函数是专门支持slice、map、channel三种结构初始化的,在new的基础上再帮忙初始化一下内部构造,不过返回的是类型
// 切片
slice := new([]int64)
fmt.Printf("slice: %p %#v \n", &slice, slice) // slice: 0xc0000ae028 &[]int64(nil)
(*slice)[0] = 1
fmt.Printf("slice: %p %#v \n", &slice, slice) // panic: runtime error: index out of range [0] with length 0
// map
map1 := new(map[string]string)
fmt.Printf("map1: %p %#v \n", &map1, map1) // map1: 0xc00000e038 &map[string]string(nil)
(*map1)["key"] = "value"
fmt.Printf("map1: %p %#v \n", &map1, map1) // panic: assignment to entry in nil map
// channel
channel := new(chan string)
fmt.Printf("channel: %p %#v \n", &channel, channel) // channel: 0xc0000ae028 (*chan string)(0xc0000ae030)
channel <- "123" // Invalid operation: channel <- "123" (send to non-chan type *chan string)
2.nil切片 与 空切片 的区别
nil切片地址是为0的 ; 空切片的地址是统一固定的
nil切片是没地址 ;空切片是有地址有内部构造没内容
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
var s1 []int // nil切片
s2 := new([]int) // *s2是nil切片
s3 := []int{} // 空切片【可以发现赋值定义出来的 和 make出来的空切片效果相同】
s4 := make([]int, 0) // 空切片
s5 := make([]int, 0) // 空切片
fmt.Printf("%p,%v\n", s1, s1)
fmt.Printf("%p,%v\n", *s2, *s2)
fmt.Printf("%p,%v\n", s3, s3)
fmt.Printf("%p,%v\n", s4, s4)
fmt.Printf("%p,%v\n", s5, s5)
fmt.Printf("s1 pointer:%+v\n", *(*reflect.SliceHeader)(unsafe.Pointer(&s1)))
fmt.Printf("s2 pointer:%+v\n", *(*reflect.SliceHeader)(unsafe.Pointer(s2)))
fmt.Printf("s3 pointer:%+v\n", *(*reflect.SliceHeader)(unsafe.Pointer(&s3)))
fmt.Printf("s4 pointer:%+v\n", *(*reflect.SliceHeader)(unsafe.Pointer(&s4)))
fmt.Printf("s5 pointer:%+v\n", *(*reflect.SliceHeader)(unsafe.Pointer(&s5)))
fmt.Printf("%v\n", (*(*reflect.SliceHeader)(unsafe.Pointer(&s1))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s3))).Data)
fmt.Printf("%v\n", (*(*reflect.SliceHeader)(unsafe.Pointer(&s2))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s3))).Data)
fmt.Printf("%v\n", (*(*reflect.SliceHeader)(unsafe.Pointer(&s4))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s4))).Data)
}
//0x0,[]
//0x0,[]
//0xdba5a0,[]
//0xdba5a0,[]
//0xdba5a0,[]可以发现使用后三种方法使用切片比前两种好【而后三种中,很明显make的方法更好,因为可以指定长度】
//s1 pointer:{Data:0 Len:0 Cap:0}
//s2 pointer:{Data:0 Len:0 Cap:0}
//s3 pointer:{Data:14394784 Len:0 Cap:0}
//s4 pointer:{Data:14394784 Len:0 Cap:0}
//s5 pointer:{Data:14394784 Len:0 Cap:0}可以发哪怕都是make出来的,s4,s5的指向仍是同一个地方
//false
//false
//true