伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

golang中make和new的区别

来源:网络转载 浏览:59次 时间:2023-08-10
0. 先说结论

Go语言中new和make是内建的两个函数,主要用来创建分配类型内存。

new可以用于对任何类型的内存分配,并返回指向该内存的指针,且内存中存储的值为对应类型的零值。new不常用,一般不用它。

make函数只用于slice、map以及channel的内存分配和初始化(非零值)。make无可替代,我们在使用slice、map和channel的时候用make进行初始化。

理解new和make首先从Golang的零值开始。


1. 零值

1.1 何为零值

零值就是变量只有声明没有初始化时系统默认设置的值。以下变量即只有声明没有初始化值,所以会被默认赋值为其对应的零值。

var i int
var f float64
var b bool
var s string
var ip *int

1.2 零值表

类型零值boolfalseuint/uint8/uint16/uint32/uint640int/int8/int16/int32/int640float32/float640complex64/complex1280+0iuintptr0byte0(对应空字符)rune0string""struct内部属性全部是其对应0值interfacenilslicenilmapnilchannilfuncnil指针nil
2. 内置函数new

2.1 new的源码

// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly
// allocated zero value of that type.
func new(Type) *Type

如源码的英文注释所示,new函数:

输入:只有一个参数Type,即分配的内存里存放的变量是什么类型

输出:返回指向内存的指针,并且内存中存放的是该类型的零值

2.2 new函数Demo

func main() {
  ip := new(int)
  fmt.Println("指向int的指针:", ip) //0xc00001a098  
  fmt.Println("int的零值:", *ip)  //0  
  
  sp := new(string)  
  fmt.Println("指向string的指针:", sp) //0xc00004e260  
  fmt.Println("string的零值:", *sp)  //""  
  
  pp := new(Person)  
  fmt.Printf("指向person的指针: %p\n", pp)          //0xc0000503e0  
  fmt.Println("person.name的零值:", (*pp).name)   //""  
  fmt.Println("person.phone的零值:", (*pp).phone) //0  
  fmt.Println("person.id的零值:", (*pp).address)  //nil  
  
  ipp := new(*int)  
  fmt.Println("指向int指针的指针:", ipp) //0xc00000a030  
  fmt.Println("int指针的零值:", *ipp)  //nil  
  
  mp := new(map[string]string)  
  fmt.Printf("指向map的指针: %p\n", mp)               //0xc0000ca028  
  fmt.Printf("指向map的指针是否为nil: %t", (*mp) == nil) //true
}
type Person struct {
  name    string  
  phone   int  
  address *string
}

看下面的这张图便一目了然。

其实,无论是map、slice还是channel其底层都是一个指针,map是一个指向hmap的指针,channel是一个指向hchan的指针,因为创建map、slice、channel时,底层分别返回的是*hmap、*reflect.SliceHeader、*hchan。其中*hchan在我的另一篇文章没名儿:Golang分享(一):channel底层原理中可以得到证明。所以我不建议大家去理解引用,也不用再纠结Go引用和指针的区别了,就是一个语法糖而已。

对上述代码我们在main函数最后新增三行初始化map。

(*m) = map[string]string{"张三丰": "武当山", "乔峰": "少林寺"}
  fmt.Printf("%p\n", (*m))  //0xc00007e4b0  
  fmt.Printf("%p\n", &(*m)) //0xc0000ca028

同样,看下面的这张图便一目了然。


3. 内置函数make

3.1 make的源码

// The make built-in function allocates and initializes an object of type
// slice, map, or chan (only). Like new, the first argument is a type, not a
// value. Unlike new, make's return type is the same as the type of its
// argument, not a pointer to it. The specification of the result depends on
// the type:
//
//  Slice: The size specifies the length. The capacity of the slice is
//  equal to its length. A second integer argument may be provided to
//  specify a different capacity; it must be no smaller than the
//  length. For example, make([]int, 0, 10) allocates an underlying array
//  of size 10 and returns a slice of length 0 and capacity 10 that is
//  backed by this underlying array.
//  Map: An empty map is allocated with enough space to hold the
//  specified number of elements. The size may be omitted, in which case
//  a small starting size is allocated.
//  Channel: The channel's buffer is initialized with the specified
//  buffer capacity. If zero, or the size is omitted, the channel is
//  unbuffered.
func make(t Type, size ...IntegerType) Type

如源码的英文注释所示,make函数:

输入:一个仅限channel、map、slice的参数Type。第二个参数用于指定长度length,第三个参数用于指定容量capacity

输出:一个指定长度和容量的channel、map或者slice

make也是用于内存分配的,但是和new不同,它只用于channel、map以及slice的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型。

3.2 make函数的Demo

func main() {
  mapDemo := make(map[string]string)  
  fmt.Println("mapDemo: ", mapDemo) //demo:  map[]  
  
  chanDemo := make(chan int, 10)  
  fmt.Println("chanDemo: ", chanDemo) //chanDemo:  0xc000116000  
  
  sliceDemo := make([]int, 10)  
  fmt.Println("sliceDemo: ", sliceDemo) //sliceDemo:  [0 0 0 0 0 0 0 0 0 0]
}

4.关于零值和初始化的理解
func main() {
  //先看make的初始化  
  mp1 := make(map[string]string)  
  mp1["乔峰"] = "少林寺"  
  fmt.Println(mp1)  
  
  //再看new的置零值  
  mp := new(map[string]string)  
  fmt.Printf("指向map的指针是否为nil: %t\n", (*mp) == nil) //true  
  //以下这行会报错,因为*mp被置为零值nil,没有初始化,  
  (*mp)["张三丰"] = "武当山"
}

new函数:返回指向map的指针,而map是零值nil,故而无法进行set操作

make函数:返回map(map本质就是指向hmap的指针),而map已经被初始化(非零值),故而可以直接进行set操作


https://www.zhihu.com/question/446317882/answer/3155926299

  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net