Go初始化函数make和new有什么区别?

简介: Go初始化函数make和new有什么区别?

1 代码演示下

代码演示:

package main
import "fmt"
func main() {
   testMap()
   fmt.Println("--------")
   testSlice()
   fmt.Println("--------")
   testChannel()
}
func testMap() {
   mmap := make(map[string]int64)
   nmap := new(map[string]int64)
   fmt.Println("&mmap = ", &mmap, "------ mmap = ", mmap)
   fmt.Println("&nmap = ", &nmap, "------ nmap = ", nmap)
   mmap = map[string]int64{"key": 100}
   nmap = &map[string]int64{"key": 100}
   fmt.Println("&mmap = ", &mmap, "------ mmap = ", mmap)
   fmt.Println("&nmap = ", &nmap, "------ nmap = ", nmap)
}
func testSlice() {
   mslice := make([]int, 0, 10)
   mslice2 := make([]int, 0)
   nslice := new([]int)
   fmt.Println("&mslice = ", &mslice, "------ mslice = ", mslice)
   fmt.Println("&mslice2 = ", &mslice2, "------ mslice2 = ", mslice2)
   fmt.Println("&nslice = ", &nslice, "------ nmap = ", nslice)
   mslice = append(mslice, 111)
   mslice2 = append(mslice2, 222)
   *nslice = append(*nslice, 333)
   fmt.Println("&mslice = ", &mslice, "------ mslice = ", mslice)
   fmt.Println("&mslice2 = ", &mslice2, "------ mslice2 = ", mslice2)
   fmt.Println("&nslice = ", &nslice, "------ nmap = ", nslice)
}
func testChannel() {
   mchan := make(chan int, 1)
   mchan2 := make(chan int, 10)
   nchan := new(chan int)
   fmt.Println("&mchan = ", &mchan, "------ mchan = ", mchan)
   fmt.Println("&mchan2 = ", &mchan2, "------ mchan2 = ", mchan2)
   fmt.Println("&nchan = ", &nchan, "------ nchan = ", nchan)
   mchan <- 10
   mchan2 <- 20
   *nchan = make(chan int, 1)
   *nchan <- 30
   fmt.Println("&mchan = ", &mchan, "------ mchan = ", <-mchan)
   fmt.Println("&mchan2 = ", &mchan2, "------ mchan2 = ", <-mchan2)
   fmt.Println("&nchan = ", &nchan, "------ nchan = ", <-*nchan)
}
复制代码

运行结果:

&mmap =  &map[] ------ mmap =  map[]
&nmap =  0xc1200ac020 ------ nmap =  &map[]
&mmap =  &map[key:100] ------ mmap =  map[key:100]
&nmap =  0xc1200ac020 ------ nmap =  &map[key:100]
--------
&mslice =  &[] ------ mslice =  []
&mslice2 =  &[] ------ mslice2 =  []
&nslice =  0xc1200ac040 ------ nmap =  &[]
&mslice =  &[111] ------ mslice =  [111]
&mslice2 =  &[222] ------ mslice2 =  [222]
&nslice =  0xc1200ac040 ------ nmap =  &[333]
--------
&mchan =  0xc1200ac048 ------ mchan =  0xc1200c6000
&mchan2 =  0xc1200ac050 ------ mchan2 =  0xc1200c8000
&nchan =  0xc1200ac058 ------ nchan =  0xc1200ac060
&mchan =  0xc1200ac048 ------ mchan =  10
&mchan2 =  0xc1200ac050 ------ mchan2 =  20
&nchan =  0xc1200ac058 ------ nchan =  30
复制代码

2 翻源码深入了解下

源码:

// 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
// 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
复制代码

简单翻译下:

//make内置函数分配并初始化一个类型对象切片、映射或chan(仅这三个)。像new一样,第一个参数是一个类型,而不是value。与new不同,make的返回类型与他的参数类型相同,而不是指向它的指针。结果的规格取决于类型:
//- Slice:大小指定长度。切片的容量为等于它的长度。可以提供第二个整数参数指定不同的容量;它必须不小于长度。例如,make([]int, 0,10)分配一个底层数组的大小为10,返回长度为0,容量为10的切片由此基础数组支持。
//- Map:为空映射分配足够的空间来容纳指定的元素数。在这种情况下,可以省略字号分配一个小的起始大小。
//- Channel:通道的缓冲区用指定的参数初始化缓冲能力。如果为零,或者省略了大小,则通道为无缓冲的。
func make(t Type, size ...IntegerType) Type
//new的内置函数分配内存。第一个参数是一个类型,不是一个value,返回的值是一个指向new的指针分配该类型的零值。
func new(Type) *Type
复制代码

3 总结下

Go语言中的 new 和 make 主要区别如下:

  • make 只能用来分配及初始化类型为 slice、map、chan 的数据。new 可以分配任意类型的数据;
  • new 分配返回的是指针,即类型 *Type。make 返回引用,即 Type;
  • new 分配的空间被清零。make 分配空间后,会进行初始化;

最后,简单总结一下Go语言中 make 和 new 关键字的实现原理,make 关键字的主要作用是创建 slice、map 和 Channel 等内置的数据结构,而 new 的主要作用是为类型申请一片内存空间,并返回指向这片内存的指针。


相关文章
|
2天前
|
存储 Go 开发者
【Go语言专栏】函数在Go语言中的使用与实现
【4月更文挑战第30天】本文介绍了Go语言中函数的使用和实现,包括函数定义、参数传递、返回值、匿名函数、变长参数、函数类型、闭包和错误处理。通过示例展示了如何定义和调用函数,以及如何利用闭包和递归解决问题。此外,还提到了Go函数作为一等公民的特性,允许存储和传递。进一步学习可参考官方文档和相关书籍。
|
7天前
|
Go
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
【4月更文挑战第21天】Go语言函数是代码组织的基本单元,用于封装可重用逻辑。本文介绍了函数定义(包括基本形式、命名、参数列表和多返回值)、调用以及匿名函数与闭包。在函数定义时,注意参数命名和注释,避免参数顺序混淆。在调用时,要检查并处理多返回值中的错误。理解闭包原理,小心处理外部变量引用,以提升代码质量和可维护性。通过实践和示例,能更好地掌握Go语言函数。
22 1
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
|
7天前
|
存储 编译器 Go
Golang深入浅出之-掌握Go语言Map:初始化、增删查改与遍历
【4月更文挑战第21天】Go语言中的`map`提供快速的键值对操作,包括初始化、增删查改和遍历。初始化时,推荐使用`make()`函数,如`make(map[string]int)`。插入和查询键值对直接通过索引访问,更新则重新赋值。删除键值对需用`delete()`函数,确保键存在。遍历map常用`for range`,注意避免在遍历中修改map。了解这些并避免易错点,能提升代码效率和可读性。
15 1
Golang深入浅出之-掌握Go语言Map:初始化、增删查改与遍历
|
8天前
|
程序员 Go API
【Go语言快速上手(二)】 分支与循环&函数讲解
【Go语言快速上手(二)】 分支与循环&函数讲解
|
8天前
|
存储 Go 开发者
Golang深入浅出之-Go语言字符串操作:常见函数与面试示例
【4月更文挑战第20天】Go语言字符串是不可变的字节序列,采用UTF-8编码。本文介绍了字符串基础,如拼接(`+`或`fmt.Sprintf()`)、长度与索引、切片、查找与替换(`strings`包)以及转换与修剪。常见问题包括字符串不可变性、UTF-8编码处理、切片与容量以及查找与替换的边界条件。通过理解和实践这些函数及注意事项,能提升Go语言编程能力。
22 0
|
13天前
|
自然语言处理 数据挖掘 程序员
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)(下)
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)(上)
26 1
|
13天前
|
数据采集 搜索推荐 Go
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)(上)
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)
25 1
|
28天前
|
供应链 算法 安全
掌握Go语言:函数精髓,定义、参数、多返回值与应用(14)
掌握Go语言:函数精髓,定义、参数、多返回值与应用(14)
|
1天前
|
设计模式 Go 调度
Golang深入浅出之-Go语言中的并发模式:Pipeline、Worker Pool等
【5月更文挑战第1天】Go语言并发模拟能力强大,Pipeline和Worker Pool是常用设计模式。Pipeline通过多阶段处理实现高效并行,常见问题包括数据竞争和死锁,可借助通道和`select`避免。Worker Pool控制并发数,防止资源消耗,需注意任务分配不均和goroutine泄露,使用缓冲通道和`sync.WaitGroup`解决。理解和实践这些模式是提升Go并发性能的关键。
11 2
|
1天前
|
JSON 监控 安全
Golang深入浅出之-Go语言中的反射(reflect):原理与实战应用
【5月更文挑战第1天】Go语言的反射允许运行时检查和修改结构,主要通过`reflect`包的`Type`和`Value`实现。然而,滥用反射可能导致代码复杂和性能下降。要安全使用,应注意避免过度使用,始终进行类型检查,并尊重封装。反射的应用包括动态接口实现、JSON序列化和元编程。理解反射原理并谨慎使用是关键,应尽量保持代码静态类型。
9 2