go语言中的new与make有什么区别

42次阅读
没有评论

共计 4729 个字符,预计需要花费 12 分钟才能阅读完成。

本篇内容主要讲解“go 语言中的 new 与 make 有什么区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“go 语言中的 new 与 make 有什么区别”吧!

new() 和 make() 的区别

以下摘录自 https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md

二者都在堆上分配内存,但是它们的行为不同,适用于不同的类型。

new(T) 为每个新的类型 T 分配一片内存,初始化为 0 并且返回类型为 * T 的内存地址:这种方法返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 T{}。make(T) 返回一个类型为 T 的初始值,它只适用于 3 种内建的引用类型:切片、map 和 channel

换言之,new 函数分配内存,make 函数初始化;下图给出了区别:

我的理解,new 返回一个变量的指针,但是这个指针指向空,你不可以直接对该指针进行操作,否则会报错,除非你将该指针指向一个该类型变量的地址。
make 返回一个该类型的变量,以切片变量为例,上面提到,make 适用于创建切片、map 和 channel, 但 new 也可以创建

package mainimport fmt func main() {// 使用 make 创建切片,返回的是变量本身 s1 := make([]int,5,10)fmt.Printf(use make create slise type %T value %v \n ,s1,s1)s1[0] = 123s1[4] = 321fmt.Printf(make s1 type %T value %v \n ,s1,s1)//# 使用 new 创建切片, 返回的是切片变量的指针 s2 := new([]int)fmt.Printf(use new create slise type %T value %v \n ,s2,s2)fmt.Printf(new s2 type %T value %v \n ,*s2,*s2)// 想要赋值的话需要使用 * 解引用 // 这里虽然不报语法错误,但是如果尝试直接使用 (*s2)[0] = 123 的话会有运行时错误,// panic: runtime error: index out of ranges2 = s1 // 需要将变量指针指向一个该类型变量的地址 (*s2)[0] = 123(*s2)[4] = 3211fmt.Printf(new s2 type %T value %v \n ,s2,s2)//s2 的修改也会影响 s1fmt.Printf(s1 type %T value %v \n ,s1,s1)m1 := make(map[string]string)m1[name] = yangyanxing m1[age] = 30 fmt.Printf(m1 use make create type:%T value %v \n ,m1,m1)m2 := new(map[string]string)fmt.Printf(m2 use new create type:%T value %v \n ,m2,m2)// 直接赋值会报 panic: assignment to entry in nil mapm2 = m1(*m2)[name] = fan // 对 m2 的修改也会影响到 m1fmt.Printf(after m2 change m1 value is %v ,m1)}

输出结果为

use make create slise type []int value [0 0 0 0 0]make s1 type []int value [123 0 0 0 321]use new create slise type *[]int value []new s2 type []int value []new s2 type *[]int value [123 0 0 0 3211]s1 type []int value [123 0 0 0 3211]m1 use make create type:map[string]string value map[name:yangyanxing age:30]m2 use new create type:*map[string]string value map[]after m2 change m1 value is map[name:fan age:30]map 的初始化

map 有以下两种初始化方法

使用 make 函数

直接使用 map 初始化

package mainimport fmt func main() {// 使用 make 初始化 mapmp2 := make(map[string]string)mp2[name]  = yangyanxing mp2[age] = 18 fmt.Println(m2 address , mp2)// out:m2 address   map[name:yangyanxing age:18]mp3 := map[string]int{} // 这里要有 {}, 花括号里如果没有内容则说明初始化了一个空字典 mp3[yang] = 18mp3[fan] = 20fmt.Println(mp3)//out:map[yang:18 fan:20]mp4 := map[string]int{yang :20, fan :21, // 即使是最后一个也要有逗号}fmt.Println(mp4)//out:map[yang:20 fan:21]mp5 := map[string]int{yang :30} // 写在同一行则不用加逗号 fmt.Println(mp5)//out: map[yang:30]mp6 := make(map[string]int,1) // 还可以给 map 加一个容量 mp6[yang] = 30fmt.Println(mp6 lens is ,len(mp6), address: , mp6)//out:mp6 lens is  1 address: map[yang:30]mp6[fan] = 31fmt.Println(mp6 lens is ,len(mp6), address: , mp6)//out:mp6 lens is  2 address: map[yang:30 fan:31]// 也可以使用 new, 但是不可以直接对其进行赋值, 因为此时它返回的是一个空指针 // 需要指向一个该类型的变量地址以后才可以进行操作 mp7 := new(map[string]int)fmt.Println(mp7)//out: map[]//(*mp7)[yang] = 100 // 会报运行时错误 mp7 = mp6//mp7[fan] = 1000 // 也不可以直接使用 mp7, 需要使用 * 先解引用 (*mp7)[yang] = 100 // 这时就不会报运行时错误 fmt.Println(mp7)//out: map[yang:100 fan:31]}

slice 切片的初始化

同样可以通过 make 和切片本身进行初始化

package mainimport fmt func main() {// 使用 make 初始化切片, 需要传一个 len 长度, 容量 cap 为可选 // 如果不传的话则长度和容量相同 sls1 := make([]int,5,10)sls1[0] = 100//append 追加到尾部, 这里有点意思 sls1  = append(sls1,200)// … 三个点,go 里的语法糖, 展开前面的切片 sls1 = append(sls1,[]int{30,40}…)fmt.Println(sls1,len(sls1),cap(sls1))//out: [100 0 0 0 0 200 30 40] 8 10sls1 = append(sls1,3,4,6)// 超过切片原有容量以后将会发生扩容 fmt.Println(sls1,len(sls1),cap(sls1))//out: [100 0 0 0 0 200 30 40 3 4 6] 11 20sls2 := make([]int,3)sls2[1] = 123fmt.Println(sls2,len(sls2),cap(sls2))//out: [0 123 0] 3 3// 直接初始化 sls3 := []int{}sls3 = append(sls3,10,20)fmt.Println(sls3,len(sls3),cap(sls3))//out: [10 20] 2 2sls4 := []int{1,2,3}sls5 :=[]int{1,2,5,// 这里的逗号不能省}fmt.Println(sls4,sls5)//out: [1 2 3] [1 2 5]// 使用 new 创建切片, 和 map 一样, 返回的也是指针, 不能直接对其进行操作 // 需要先指向一个变量的地址 sls6 := new([]int)fmt.Println(sls6)//out: []sls6 = sls4fmt.Println(sls6) //out: [1 2 3]}

array 数组的初始化

数组不能使用 make 初始化, 但是可以使用 new 初始化

package mainimport fmt type person struct {name stringage int}func main() {fmt.Println( 数组的初始化)// 声明并初始化一个空数组, 里面的元素值为类型的零值 arr1 := [2]int{}fmt.Println(arr1) //out: [0 0]// 初始化时将元素值写上 arr2 := [2]int{1,3}fmt.Println(arr2) //out: [1 3]// 只写一个, 不写的是零值 arr3 := [2]int{1}fmt.Println(arr3) //out: [1 0]//arr4 := make([2]int) // 数组不能使用 makevar arr5 [2]intarr5[0] = 100fmt.Println(arr5)//[100 0]// 不指定数组大小, 使用 … 三点号让其自动展开计算 arr6 := […]int{2,4,6,8}fmt.Println(arr6,len(arr6))//out: [2 4 6 8] 4// 使用 new 创建一个数组, 得到的是一个指针 arr7 := new([3]int)fmt.Println(arr7)//out: [0 0 0]// 可以直接对指针进行操作 arr7[0] = 3// 和使用 * 解引用作用一样 (*arr7)[1] = 4fmt.Println(arr7) //out: [3 4 0]}

struct 结构体的初始化

结构体不能使用 make, 需要使用 new 和结构体本身

package mainimport fmt type person struct {name stringage int}func main() {fmt.Println( 结构体的初始化)// 使用 new, 返回结构体指针 stru1 := new(person)fmt.Println(stru1)//out {0} , 默认是字段的零值 // 可以直接使用这个指针来操作变量 // 和使用 * 解引用效果一样 stru1.name = yangyanxing (*stru1).age = 18fmt.Println(stru1,*stru1) // {yangyanxing 18} {yangyanxing 18}// 只指定一个字段, 没有指定的默认零值 stru2 := person{name: fan}fmt.Println(stru2) //{fan 0}// 全部指定, 字段的顺序可以不按照定义时的顺序 stru3 := person{age:18,name: yang}fmt.Println(stru3) //{yang 18}// 按照结构体顺序初始化, 这时元素的值必须都写全了 stru4 := person{fan ,17}fmt.Println(stru4) //{fan 17}}

到此,相信大家对“go 语言中的 new 与 make 有什么区别”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-01发表,共计4729字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)