陈哈哈的博客

Go语言重点笔记-如何理解内部函数make和new

2018-05-18

如何理解 make() 和 new()

new()是常规用法

new()函数与C/C++、Java等new关键字方法类似,创建并返回指定类型的指针/引用。

make()是变通用法

make()函数,它更像是new()带参数封装函数,用来解决new()函数无法指定slice, map, chan等内置数据结构在初始化时,需要指定容量的问题。

一、正统创建对象指针函数:new()

函数原型:func new(Type) *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.

new()内置函数用于申请内存。第一个参数是数据类型,而非一个值。函数返回指定类型的零值的内存地址指针。

二、带参数的工具函数:make()

函数原型:func make(t Type, size ...IntegerType) Type

官方注释:

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, Map, Chan.

make()函数所支持的类型来看,它只支持slicemapchan三种,它负责对这些类型进行内存分配和初始化。
new()函数不同的是,它的返回值是参数所指定的类型,而非指针。

其中这三个类型,各有不同的参数和内存操作:

2.1 Slice 切片类型。

切片类型的make函数,接受2到3个参数:

make([]string, 0, 10)

  1. [必选] 切片类型;
  2. [必选] 切片长度;
  3. [可选] 切片容量;

第三个参数,如果没有指定,则创建长度与容量相同的切片。因此,s := make([]string, 5) 会创建一个长度为5,容量也是5的切片,切片的内容为5个空值。

2.1 Map 映射类型

Map类型的make函数,接受1-2个参数:

m := make(map[string]string, 100)

  1. [必选] 映射类型;
  2. [可选] 映射容量;

创建空的Map时,它已经申请足够的内存空间大小来储存K-V元素。这种情况下,容量大小可以忽略:

m := make(map[string]string)

2.2 Channel 通道

Channel类型的Make函数,接受1-2个参数。其中第二个参数将决定Channel的阻塞特性。

  1. [必选] Channel类型;
  2. [可选] Channel缓存大小;

如果第二个参数“缓存大小”不设置,或者为0。则创建一个无缓存的通道,否则创建指定缓存大小的通道。

2.2.1 无缓存的通道 unbuffered channel

内部缓存队列为0。这意味着,接收方和发送方在读写此通道时,它们是同步操作的:

接收方会阻塞在读操作上(v := <-ch),直到发送方往此通道发数据(或者通道被关闭)。而发送方也会阻塞在写操作上(ch <- v),直到接收方读数据。

2.2.2 有缓存的通道 buffered channel

内部有指定大小的缓存队列。接收方和发送方,由于缓存列队的存在,它们可以异步地读写数据。

接收方会顺序地从队列中读出一个数据(GetAndRemove),队列为空时阻塞,直到发送方往此通道发数据(或者通道被关闭)。
同样地,发送方顺序地向队列写入数据,如果内部缓存满了,阻塞等待队列有空位。