Go 面试题: new 和 make 是什么,差别在哪?

如有任何问题或建议,欢迎及时交流和碰撞。个人公众号是 【脑子进煎鱼了】,GitHub 地址: https://github.com/eddycjy

你们好,我是煎鱼。git

在 Go 语言中,有两个比较雷同的内置函数,分别是 newmake 方法,其主要用途都是用于分配相应类型的内存空间。github

看上去 newmake 都是分配内存的,那他们有什么区别呢?这个细节点也成为了避免少 Go 语言工程师的面试题之一,值得你们一看。golang

在今天这篇文章中咱们未来解答这个问题。面试

基本特性

make

在 Go 语言中,内置函数 make 仅支持 slicemapchannel 三种数据类型的内存建立,其返回值是所建立类型的自己,而不是新的指针引用数据结构

函数签名以下:架构

func make(t Type, size ...IntegerType) Type

具体使用示例:函数

func main() {
    v1 := make([]int, 1, 5)
    v2 := make(map[int]bool, 5)
    v3 := make(chan int, 1)
    
    fmt.Println(v1, v2, v3)
}

在代码中,咱们分别对三种类型调用了 make 函数进行了初始化。你会发现有的入参是有多个长度指定,有的没有。微服务

这块的区别主要是长度(len)和容量(cap)的指定,有的类型是没有容量这一说法,所以天然也就没法指定。spa

输出结果:设计

[0] map[] 0xc000044070

有一个细节点要注意,调用 make 函数去初始化切片(slice)的类型时,会带有零值,须要明确是否须要。

见过很多的小伙伴在这上面踩坑。

new

在 Go 语言中,内置函数 new 能够对类型进行内存建立和初始化。其返回值是所建立类型的指针引用,与 make 函数在实质细节上存在区别。

函数签名以下:

func new(Type) *Type

具体使用示例:

type T struct {
    Name string
}

func main() {
    v := new(T)
    v.Name = "煎鱼"
}

从上面的例子的效果来看,是否是似曾类似?其实与下面这种方式的同样的:

func main() {
    v := T{}
    v.Name = "煎鱼"
}

输出结果均是:

&{Name:煎鱼}

其实 new 函数在平常工程代码中是比较少见的,由于他可被替代。

通常会直接用快捷的 T{} 来进行初始化,由于常规的结构体都会带有结构体的字面属性:

func NewT() *T {
    return &T{Name: "煎鱼"}
}

这种初始化方式更方便。

区别在哪里

可能会有的小伙伴会疑惑一点,就是 new 函数也能初始化 make 的三种类型:

v1 := new(chan bool)
    v2 := new(map[string]struct{})

make 函数的区别,优点是什么呢?

本质上在于 make 函数在初始化时,会初始化 slicechanmap 类型的内部数据结构,new 函数并不会。

例如:在 map 类型中,合理的长度(len)和容量(cap)能够提升效率和减小开销。

更进一步的区别:

  • make 函数:

    • 可以建立类型所需的内存空间,返回引用类型的自己。
    • 具备使用范围的局限性,仅支持 channelmapslice 三种类型。
    • 具备独特的优点,make 函数会对三种类型的内部数据结构(长度、容量等)赋值。
  • new 函数:

    • 可以建立并分配类型所需的内存空间,返回指针引用(指向内存的指针)。
    • 可被替代,可以经过字面值快速初始化。

总结

在这篇文章中,咱们介绍了 Go 语言中 makenew 函数的使用,并针对其区别点进行了分析。

可能会有小伙伴疑惑,那 newmake 函数所初始化出来的内存,是分配在堆仍是栈上呢?

这就涉及到 Go 语言中的 “逃逸分析” 了(我公众号前几天的文章有发),若是所初始化的变量不须要在当前做用域外生存,那么理论上就不须要初始化在堆上。

个人公众号

分享 Go 语言、微服务架构和奇怪的系统设计,欢迎你们关注个人公众号和我进行交流和沟通。

最好的关系是互相成就,各位的点赞就是煎鱼创做的最大动力,感谢支持。

相关文章
相关标签/搜索