new,make,nil切片,空切片

66 阅读2分钟

1.new() 与 make() 的区别

  • new对于简单的类型和数组,比如int ,char,数组的初始化,不仅会初始化出指针,由于内部构造单一,所以内部也帮忙构造出来【自己的目前的猜想】
  • new函数去初始化,主要是为类型申请一片内存空间,返回执行内存的指针
  • slicemapchan初始化后还是不能使用,会触发panic,这是因为new对于这三种结构只能做到给整体一个地址,至于地址里面的构造是不会帮忙初始化出来的,因为new自己不知道给 slicemapchannel 多大的长度【自己的目前的猜想】
  • make函数是专门支持 slicemapchannel 三种结构初始化的,在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