C++繞暈了的指針,Go中是怎樣的呢?

區別於C/C++中的指針,Go語言中的指針不能進行偏移和運算,是安全指針。

要搞明白Go語言中的指針需要先知道3個概念:指針地址、指針類型和指針取值。

Go語言中的指針

Go語言中的函數傳參都是值拷貝,當我們想要修改某個變量的時候,我們可以創建一個指向該變量地址的指針變量。傳遞數據使用指針,而無須拷貝數據。類型指針不能進行偏移和運算。Go語言中的指針操作非常簡單,只需要記住兩個符號:&(取地址)和*(根據地址取值)。

指針地址和指針類型

每個變量在運行時都擁有一個地址,這個地址代表變量在內存中的位置。Go語言中使用&字符放在變量前面對變量進行“取地址”操作。 Go語言中的值類型(int、float、bool、string、array、struct)都有對應的指針類型,如:*int、*int64、*string等。

取變量指針的語法如下:

  • ptr := &v // v的類型為T

其中:

  • v:代表被取地址的變量,類型為T
  • ptr:用於接收地址的變量,ptr的類型就為*T,稱做T的指針類型。*代表指針。

舉個例子:

被C/C++繞暈了的指針,Go中是怎樣的呢?

我們來看一下b := &a的圖示:

被C/C++繞暈了的指針,Go中是怎樣的呢?

指針取值

在對普通變量使用&操作符取地址後會獲得這個變量的指針,然後可以對指針使用*操作,也就是指針取值,代碼如下。

被C/C++繞暈了的指針,Go中是怎樣的呢?

輸出如下:

被C/C++繞暈了的指針,Go中是怎樣的呢?

總結: 取地址操作符&和取值操作符*是一對互補操作符,&取出地址,*根據地址取出地址指向的值。

變量、指針地址、指針變量、取地址、取值的相互關係和特性如下:

  • 對變量進行取地址(&)操作,可以獲得這個變量的指針變量。
  • 指針變量的值是指針地址。
  • 對指針變量進行取值(*)操作,可以獲得指針變量指向的原變量的值。

指針傳值示例:

被C/C++繞暈了的指針,Go中是怎樣的呢?

new和make

我們先來看一個例子:

被C/C++繞暈了的指針,Go中是怎樣的呢?

執行上面的代碼會引發panic,為什麼呢? 在Go語言中對於引用類型的變量,我們在使用的時候不僅要聲明它,還要為它分配內存空間,否則我們的值就沒辦法存儲。而對於值類型的聲明不需要分配內存空間,是因為它們在聲明的時候已經默認分配好了內存空間。要分配內存,就引出來今天的new和make。 Go語言中new和make是內建的兩個函數,主要用來分配內存。

new

new是一個內置的函數,它的函數簽名如下:

被C/C++繞暈了的指針,Go中是怎樣的呢?

其中,

  • Type表示類型,new函數只接受一個參數,這個參數是一個類型
  • *Type表示類型指針,new函數返回一個指向該類型內存地址的指針。

new函數不太常用,使用new函數得到的是一個類型的指針,並且該指針對應的值為該類型的零值。舉個例子:

被C/C++繞暈了的指針,Go中是怎樣的呢?

本節開始的示例代碼中var a *int只是聲明瞭一個指針變量a但是沒有初始化,指針作為引用類型需要初始化後才會擁有內存空間,才可以給它賦值。應該按照如下方式使用內置的new函數對a進行初始化之後就可以正常對其賦值了:

被C/C++繞暈了的指針,Go中是怎樣的呢?

make

make也是用於內存分配的,區別於new,它只用於slice、map以及chan的內存創建,而且它返回的類型就是這三個類型本身,而不是他們的指針類型,因為這三種類型就是引用類型,所以就沒有必要返回他們的指針了。make函數的函數簽名如下:

被C/C++繞暈了的指針,Go中是怎樣的呢?

make函數是無可替代的,我們在使用slice、map以及channel的時候,都需要使用make進行初始化,然後才可以對它們進行操作。這個我們在上一章中都有說明,關於channel我們會在後續的章節詳細說明。

本節開始的示例中var b map[string]int只是聲明變量b是一個map類型的變量,需要像下面的示例代碼一樣使用make函數進行初始化操作之後,才能對其進行鍵值對賦值:

被C/C++繞暈了的指針,Go中是怎樣的呢?

new與make的區別

  1. 二者都是用來做內存分配的。
  2. make只用於slice、map以及channel的初始化,返回的還是這三個引用類型本身;
  3. 而new用於類型的內存分配,並且內存對應的值為類型零值,返回的是指向類型的指針。

原文鏈接:https://www.liwenzhou.com/posts/Go/07_pointer/

"


分享到:


相關文章: