Golang指針隱式間接引用詳解
1、Golang指針
在介紹Golang指針隱式間接引用前,先簡單說下Go 語言的指針 (Pointer),一個指針可以指向任何一個值的內存地址 它指向那個值的內存地址,在 32 位機器上占用 4 個字節(jié),在 64 位機器上占用 8 個字節(jié),并且與它所指向的值的大小無關。大致上理解如下:
- 變量名前的 & 符號,是取變量的內存地址,不是取值;
- 數(shù)據(jù)類型前的 * 符號,代表要儲存的是對應數(shù)據(jù)類型的內存地址,不是存值;
- 變量名前的 * 符號,代表從內存地址中取值 (Dereferencing)。
使用一個指針引用一個值被稱為間接引用。
注意 1:golang 指針Dereferencing(解引用)是什么意思?
在 Go 語言中,指針解引用(dereferencing)是指通過指針訪問指針所指向的內存地址上存儲的值。在指針變量前加上 * 符號可以進行指針解引用操作。指針解引用會返回指針所指向的內存地址上存儲的值。例如,假設有一個指向int類型變量的指針:
var x int = 42 var p *int = &x
要訪問p指針指向的值,可以使用指針解引用:
fmt.Println(*p) // 輸出:42
可以看到,使用操作符訪問指針指向的值時,需要將其放置在指針變量的前面。如果嘗試使用操作符訪問一個空指針,會引發(fā)運行時錯誤。因此,在解引用指針之前,通常需要確保指針不是空指針。
注意 2:在Go語言中,直接砍掉了 C 語言指針最復雜的指針運算部分,只留下了獲取指針(&
運算符)和獲取對象(*
運算符)的運算,用法和C語言很類似。但不同的是,Go語言中沒有->
操作符來調用指針所屬的成員,而與一般對象一樣,都是使用.
來調用。
注意 3:Go 語言中一個指針被定義后沒有分配到任何變量時,它的值為nil
。
2、new函數(shù)
在 Go 語言中,new 函數(shù)用于動態(tài)地分配內存,返回一個指向新分配的零值的指針。它的語法如下:
func new(Type) *Type
其中,Type 表示要分配的內存的類型,new 函數(shù)返回一個指向 Type 類型的新分配的零值的指針。但是需要注意的是,new 函數(shù)只分配內存,并返回指向新分配的零值的指針,而不會初始化該內存。
注意 1:用new(structName):這個方法得到的是*structName類型,即類的指針類型;用structName{init para}:這個方法得到的是structName類型,即類的實例類型,不是指針。
注意 2:new函數(shù)更多細節(jié)介紹請參見《Go語言new( )函數(shù)》這篇博文。
3、Golang指針隱式間接引用
Go 語言自帶指針隱式解引用 :對于一些復雜類型的指針, 如果要訪問成員變量時候需要寫成類似*p.field
的形式時,只需要p.field
即可訪問相應的成員。以下復雜類型自帶指針隱式解引用:
3.1 結構體類型指針隱式間接引用
結構體字段可以通過結構體指針來訪問。如果我們有一個指向結構體的指針p
,那么可以通過(*p).X
來訪問其字段X
。不過這么寫太啰嗦了,所以語言也允許我們使用隱式間接引用,直接寫p.X
就可以。示例代碼如下:
package main import ( "fmt" ) type Student struct { name string age int weight float32 score []int } func main(){ pp := new(Student) //使用 new 關鍵字創(chuàng)建一個指針 *pp = Student{"qishuangming", 23, 65.0, []int{2, 3, 6}} fmt.Printf("stu pp have %d subjects\n", len((*pp).score)) //按照我們對指針的了解,對Student結構體對象pp顯示賦值的話需要使用解引用語法進行賦值,但是實際編碼時都會省去*,寫法如下行所示。 fmt.Printf("stu pp have %d subjects\n", len(pp.score)) //編譯器會自動將指針解引用,并訪問結構體中的對應字段,這個過程被稱為隱式間接引用。 }
3.2 數(shù)組類型指針隱式間接引用
同樣指向數(shù)組的指針可以隱式解引用數(shù)組中的元素。
var arr [3]int p := &arr p[0] = 1 // 等價于 (*p)[0] = 1
3.3 切片類型指針隱式間接引用
切片實際上是對底層數(shù)組的封裝,因此指向切片的指針可以隱式解引用切片中的元素。
s := []int{1, 2, 3} p := &s p[0] = 4 // 等價于 (*p)[0] = 4
3.4 字典類型隱式間接引用
map 是引用類型,當我們使用 map
類型的變量訪問元素時,也不需要使用 *
運算符進行解引用,Golang 會自動幫我們解引用。
m := map[string]int{"a": 1, "b": 2} fmt.Println(m["a"]) // 隱式解引用
3.5func 類型隱式間接引用
在 Golang 中,函數(shù)類型也是一種類型,它可以使用指針類型來表示函數(shù)的地址。如果我們定義了一個函數(shù)類型的變量,并將一個函數(shù)的地址賦值給它,那么我們可以直接調用該變量,并且不需要使用 *
運算符進行解引用。
例如,以下代碼演示了函數(shù)類型指針的隱式解引用:
type Add func(a, b int) int func main() { var add Add add = func(a, b int) int { return a + b } println(add) //0x10cf168 sum := add(1, 2) // 隱式解引用 fmt.Println(sum) }
在上面的代碼中,我們定義了一個函數(shù)類型 Add
,它接受兩個 int
類型的參數(shù)并返回一個 int
類型的值。我們定義了一個變量 add
,它的類型是 Add
。我們將一個函數(shù)的地址賦值給了 add
變量,然后直接調用了 add
變量,不需要使用 *
運算符進行解引用。
注意 1:函數(shù)類型指針的隱式解引用僅適用于函數(shù)類型變量的調用,而不適用于訪問函數(shù)類型變量的成員。如果我們想要訪問函數(shù)類型變量的成員,還是需要使用 *
運算符進行解引用。
注意 2:在 Go 中,基本類型(如 int、float、bool 等)以及字符串類型等非引用類型都沒有指針隱式解引用的行為。這意味著,如果需要訪問基本類型的指針指向的值,必須顯式地使用 * 運算符來解引用指針。下面是一個示例:
var i int p := &i *p = 1 // 顯式解引用指針來修改指針所指向的值 fmt.Println(i) // 輸出 1
另外,對于基本類型而言,使用指針可能會導致性能下降。因此,在使用指針時應該謹慎,并且只在必要的情況下使用指針來傳遞數(shù)據(jù)。
4、總結
在 Go 中,指針隱式解引用是指通過指針直接訪問指針所指向的值,而不需要顯式地使用 * 運算符來解引用指針。對于一些復雜類型的指針(結構體類型指針、數(shù)組/切片類型指針、字典類型、func類型), 如果要訪問成員變量時候需要寫成類似*p.field
的形式時,只需要p.field
即可訪問相應的成員。
到此這篇關于Golang指針隱式間接引用的文章就介紹到這了,更多相關Golang指針內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Go語言異常處理(Panic和recovering)用法詳解
異常處理是程序健壯性的關鍵,往往開發(fā)人員的開發(fā)經(jīng)驗的多少從異常部分處理上就能得到體現(xiàn)。Go語言中沒有Try?Catch?Exception機制,但是提供了panic-and-recover機制,本文就來詳細講講他們的用法2022-07-07