前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学妹问 Golang 的 new 与make 是什么?

学妹问 Golang 的 new 与make 是什么?

作者头像
后端时光
发布2022-08-19 10:18:56
2850
发布2022-08-19 10:18:56
举报
文章被收录于专栏:后端时光

本篇文章基于 Golang 1.17.2

胖虎坐在公司工位上正在吃刚才买的包子。

新来的小学妹就匆忙地跑过来,慌慌张张说:“学长,不好了,线上代码出现问题了。”

胖虎赶紧放下包子,来不及擦嘴,迅速掏出电脑,边打开电脑边问“你知道哪里报错吗,为什么报错吗”

学妹:“不知道啊……”

胖虎:“……行吧,我自己看下吧。”

学妹从来没有见过如此严肃的学长,大气也不敢喘,也不敢走,就默默的看学长在查问题。

胖虎:“找到了,这是谁写的代码啊,map 使用了 new 初始化”

代码语言:javascript
复制
map1 := new(map[string]string)

学妹:“

是我,学长……”

胖虎:“行吧,看在你是我学妹份上,今天跟你简单科普一下吧”

变量声明的方式

代码语言:javascript
复制
 var test1 int
 var test2 string

我们可以通过 var+变量名称+变量类型 进行声明变量,当我们没有给它赋值的时候,它们的结果是变量类型的零值。

比如说 string 的零值是"", int 的零值是0,引用类型的零值是nil。

以上两种类型我们可以直接使用,但如果把它改成指针会怎么样呢?

代码语言:javascript
复制
package main

import "fmt"

func main() {
  var test *string
  fmt.Println(test)
  *test = "测试"
}

执行结果如下:

这是为什么呢,因为对于引用类型的变量,不仅要声明,并且还要给它分配内存。怎么给它分配内存呢?这就要用到了new了

什么是new

new 是 Golang 的内置函数,源代码如下:

大意是,分配内存的内置函数,第一个参数是类型,而不是具体的值,返回值是该类型的指针。分配的值是该类型零值的指针。

“我知道怎么改了

” 学妹兴奋的说道,说完便在编辑器加了两行代码。

代码语言:javascript
复制
package main

import "fmt"

func main() {
  var test *string
  fmt.Println(test)
  test = new(string)
  *test = "测试"
  fmt.Println(*test)
}

胖虎:“恩,不错,学得挺快的嘛,那我再问你一下,复合类型的slicemapchan使用 new 后可以使用吗?为什么呢”

学妹:“这你刚才没说啊,我不知道

胖虎:“咱们可以敲下代码,演示一下嘛”

代码语言:javascript
复制
package main

import "fmt"

func main() {
  testMap := new(map[string]string)
  (*testMap)["aa"] = "aa"
  fmt.Println(testMap)
}

执行下代码,竟然报错了,“这是为什么呢?”

胖虎:“真相只有一个,那就是,map 底层是结构体,这样说,你可能不理解,举个🌰吧。”

Talk is cheap. Show me the code

代码语言:javascript
复制
package main

import "fmt"

type XueMei struct {
  age          *int64 `json:"age"`
  BoyFiriendYn bool   `json:"boy_firiend_yn"`
}

func main() {
  test := new(XueMei)
  //是否有男朋友
  test.BoyFiriendYn = false

  //此处代码会导致panic
  //panic: runtime error: invalid memory address or nil pointer dereference
  //[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x108a0e9]
  *test.age = 1
}

也就是说它里面的成员变量仍未进行初始化,所以它们几个初始化要使用make来进行。

学妹崇拜的眼光“ 学长你懂得真多,你还能说说什么是 make 吗?”

什么是make

make 也是用于内存分配的内置函数,但是和new不同,源码如下图所示。

大意是make内置函数分配并初始化一个slicemapchan类型的对象。像new函数一样,第一个参数是类型,而不是值。

new不同,make的返回类型与其参数的类型相同,而不是指向它的指针。结果的取决于传入的类型。

并且 slice在 make 的时候,第二个参数必须传递,也就是切片的长度。否则会编译失败。

new函数底层实现

new函数底层主要是调用go1.17/src/runtime/malloc.go中的 newobject 方法。

这里可以看到 newobject 方法,底层调用 mallocgc 方法的时候,needzero 传的是 true ,所以返回值是传入类型零值的指针。

make函数底层实现

通过执行以下命令go tool compile -N -l -S file.go

我们可以看到make函数初始化

slice调用的是runtime.makesliceruntime.makeslice64这两个方法.

代码语言:javascript
复制
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer

map调用的是runtime.makemap64runtime.makemapruntime.makemap_small这三个方法.

代码语言:javascript
复制
func makemap64(mapType *byte, hint int64, mapbuf *any) (hmap map[any]any)
func makemap(mapType *byte, hint int, mapbuf *any) (hmap map[any]any)
func makemap_small() (hmap map[any]any)

chan分别调用的是runtime.makechan64runtime.makechan这三个方法.

代码语言:javascript
复制
func makechan64(chanType *byte, size int64) (hchan chan any)
func makechan(chanType *byte, size int) (hchan chan any)

感兴趣的同学可以去看下源代码

学妹:“懂了学长,那我总结一下吧”

胖虎:“恩,不错不错,果然没有看错你,今天晚上有时间吗,跟大家分享一下你今天学到的知识吧。”

学妹:“改天可以吗?晚上男朋友约我一起吃饭了”

胖虎os:当初面试时候她说没有男朋友,才把她招进来的,怎么现在突然有男朋友了?没想到小丑竟然是我自己

福利

我为大家整理了一些学习资料礼包,关注公众号回复指令:【Golang】、【操作系统】、【Linux】、【LeetCode】、【Golang电子书】即可获得相应学习资料!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端时光 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 变量声明的方式
  • 什么是new
  • Talk is cheap. Show me the code
    • 什么是make
      • new函数底层实现
        • make函数底层实现
          • 福利
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档