【go】golang中置new()函數和make()函數的區別


Go語言中的內建函數new和make是兩個用於內存分配的原語(allocation primitives),其功能相似,卻有本質區別。

1、new

官方文檔

// 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

翻譯如下:

內建函數 new 用來分配內存,第一個參數是一個類型,不是一個值,返回值是一個指向分配零值的指針

new和其他語言中的同名函數一樣,new(t)分配了零值填充的類型為T內存空間,並且返回其地址,即一個*t類型的值。返回的永遠是類型的指針,指向分配類型的內存地址

 

它並不初始化內存,只是將其置零。*t指向的內容的值為零(zero value)。注意並不是指針為零。

2、make

官方文檔

//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.

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

翻譯如下:

內建函數 make 用來為 slice,map 或 chan 類型分配內存和初始化一個對象(注意:只能用在這三種類型上),跟 new 類似,第一個參數也是一個類型而不是一個值,跟 new 不同的是,make 返回類型的本身而不是指針,而返回值也依賴於具體傳入的類型,因為這三種類型就是引用類型,所以就沒有必要返回他們的指針了

make(t, args)與new(t)的功能區別是,make只能創建slice、map和channel,並且返回一個初始化的類型為t的值(而不是*t)。

注意,因為這三種類型是引用類型,所以必須得初始化,但是 不是置為零值,這個和new是不一樣的。

3、為什么slice、map和channel要由make創建呢?

先來看一下以上三個數據結構的源碼

slice

type slice struct {
    array unsafe.Pointer
    len int
    cap int
}

slice的結構體由3部分構成,Pointer 是指向一個數組的指針,len 代表當前切片的長度,cap 是當前切片的容量。

map

// A header for a Go map.
type hmap struct {
    count int 
    flags uint8
    B uint8 
    noverflow uint16 
    hash0 uint32 
    buckets unsafe.Pointer 
    oldbuckets unsafe.Pointer 
    nevacuate uintptr 
    extra *mapextra 
}

channel

type hchan struct {
    qcount uint 
    dataqsiz uint 
    buf unsafe.Pointer
    elemsize uint16 
    closed uint32 
    elemtype *_type 
    sendx uint 
    recvx uint 
    recvq waitq 
    sendq waitq 
    lock mutex
}

看到沒有,都是需要分配內存的

4、總結

new和make都在堆上分配內存,但是它們的行為不同,適用於不同的類型。

new(T) 為每個新的類型T分配一片內存,初始化為 0 並且返回類型為*T的內存地址:這種方法 返回一個指向類型為 T,值為 0 的地址的指針,它適用於值類型如數組和結構體;它相當於 &T{}。

make(T) 返回一個類型為 T 的初始值,是三個引用類型本身,它只適用於3種內建的引用類型:slice、map 和 channel。

換言之,new 函數分配內存,make 函數初始化;

其實new不常用

所以有new這個內置函數,可以給我們分配一塊內存讓我們使用,但是現實的編碼中,它是不常用的。我們通常都是采用短語句聲明以及結構體的字面量達到我們的目的,比如:

i:=0
u:=user{}

這樣更簡潔方便,而且不會涉及到指針這種比麻煩的操作。

make函數是無可替代的,我們在使用slice、map以及channel的時候,還是要使用make進行初始化,然后才才可以對他們進行操作。

package main

import (
	"fmt"
)

func main() {
    p := new([]int) //p == nil; with len and cap 0
    fmt.Println(p)

    v := make([]int, 10, 50) // v is initialed with len 10, cap 50
    fmt.Println(v)

    /*********Output****************
        &[]
        [0 0 0 0 0 0 0 0 0 0]
    *********************************/

    (*p)[0] = 18        // panic: runtime error: index out of range
                        // because p is a nil pointer, with len and cap 0
    v[1] = 18           // ok
    
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM