首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go 为什么要有new 和 make

go 为什么要有new 和 make

作者头像
solate
发布2022-05-09 13:28:42
6760
发布2022-05-09 13:28:42
举报
文章被收录于专栏:solate 杂货铺solate 杂货铺

go 为什么要有new 和 make

Go 语言就会根据变量的类型自动分配相应的内存。

值类型

对于基础类型,go语言会根据类型自动分配内存,并赋值这个类型的零值。

如 string 类型的零值是一个空字符串

	var a string
	fmt.Println(a, &a) // 空串 0xc000010230

引用类型

应用类型本质其实拿到的是一个指针,指针的零值是nil, 所以如果不显式声明,是不会自动分配内存的。

	var a *string
	*a = "test"
	fmt.Println(a)
	
// panic: runtime error: invalid memory address or nil pointer dereference	

指针类型没有分配内存无法使用,强行用会报指针异常错误

new()

指针变量默认是没有分配内存的,那么需要使用new()函数来分配内存

	var a *string
	a = new(string)
	*a = "test"
	fmt.Println(a, &a, *a) // 0xc000010230 0xc00000e028 test

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(struct)后,得到的就是一个指向结构体内存块的指针。

	type person struct {
		name string
		age int
	}
	p := new(person)
	fmt.Println(p, &p) // &{ 0} 0xc000124018

make()

make 函数创建 map 的时候,其实调用的是 makemap 函数

//src/runtime/map.go

// makemap implements Go map creation for make(map[k]v, hint).
// If the compiler has determined that the map or the first bucket
// can be created on the stack, h and/or bucket may be non-nil.
// If h != nil, the map can be created directly in h.
// If h.buckets != nil, bucket pointed to can be used as the first bucket.
func makemap(t *maptype, hint int, h *hmap) *hmap {

makemap 函数返回的是 *hmap 类型,而 hmap 是一个结构体, 代码

//src/runtime/map.go


// A header for a Go map.
type hmap struct {
	// Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go.
	// Make sure this stays in sync with the compiler's definition.
	count     int // # live cells == size of map.  Must be first (used by len() builtin)
	flags     uint8
	B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
	noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
	hash0     uint32 // hash seed

	buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

	extra *mapextra // optional fields
}

这样的结构体就比较复杂了,需要提前知道map的大小count, 存储的桶。如果简单的使用new返回一个*hmap, 并不能很好的使用,这个使用就需要用make函数

m:=make(map[string]int,10)

make函数类似于工厂方法,创建一类相同结构的类型。 如上根据传递它的 K-V 键值对类型,创建不同类型的 map,同时可以初始化 map 的大小。

总结

  1. new 函数只用于分配内存,并且把内存清零,也就是返回一个指向对应类型零值的指针
  2. make 函数只用于 slice、chan 和 map 这三种内置类型的创建和初始化,因为这三种类型的结构比较复杂,比如 slice 要提前初始化好内部元素的类型,slice 的长度和容量等

所以综上:

1. new 是为了解决引用类型,也就是指针刚开始指向一个nil,需要分配内存空间才能使用这个问题设计的

2. make 是为了解决光new一块空间后并不能达到目标,还需要添加长度、容量等其他条件才能使用,所以设计了make函数。

每个设计的关键字都是为了解决一类问题的,多多思考有助于我们更好的理解对应的知识。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • go 为什么要有new 和 make
    • 值类型
      • 引用类型
        • new()
          • make()
            • 总结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档