Golang指針隱式間接引用詳解
1、Golang指針
在介紹Golang指針隱式間接引用前,先簡(jiǎn)單說(shuō)下Go 語(yǔ)言的指針 (Pointer),一個(gè)指針可以指向任何一個(gè)值的內(nèi)存地址 它指向那個(gè)值的內(nèi)存地址,在 32 位機(jī)器上占用 4 個(gè)字節(jié),在 64 位機(jī)器上占用 8 個(gè)字節(jié),并且與它所指向的值的大小無(wú)關(guān)。大致上理解如下:
- 變量名前的 & 符號(hào),是取變量的內(nèi)存地址,不是取值;
- 數(shù)據(jù)類型前的 * 符號(hào),代表要儲(chǔ)存的是對(duì)應(yīng)數(shù)據(jù)類型的內(nèi)存地址,不是存值;
- 變量名前的 * 符號(hào),代表從內(nèi)存地址中取值 (Dereferencing)。
使用一個(gè)指針引用一個(gè)值被稱為間接引用。
注意 1:golang 指針Dereferencing(解引用)是什么意思?
在 Go 語(yǔ)言中,指針解引用(dereferencing)是指通過(guò)指針訪問(wèn)指針?biāo)赶虻膬?nèi)存地址上存儲(chǔ)的值。在指針變量前加上 * 符號(hào)可以進(jìn)行指針解引用操作。指針解引用會(huì)返回指針?biāo)赶虻膬?nèi)存地址上存儲(chǔ)的值。例如,假設(shè)有一個(gè)指向int類型變量的指針:
var x int = 42 var p *int = &x
要訪問(wèn)p指針指向的值,可以使用指針解引用:
fmt.Println(*p) // 輸出:42
可以看到,使用操作符訪問(wèn)指針指向的值時(shí),需要將其放置在指針變量的前面。如果嘗試使用操作符訪問(wèn)一個(gè)空指針,會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤。因此,在解引用指針之前,通常需要確保指針不是空指針。
注意 2:在Go語(yǔ)言中,直接砍掉了 C 語(yǔ)言指針最復(fù)雜的指針運(yùn)算部分,只留下了獲取指針(&運(yùn)算符)和獲取對(duì)象(*運(yùn)算符)的運(yùn)算,用法和C語(yǔ)言很類似。但不同的是,Go語(yǔ)言中沒(méi)有->操作符來(lái)調(diào)用指針?biāo)鶎俚某蓡T,而與一般對(duì)象一樣,都是使用.來(lái)調(diào)用。
注意 3:Go 語(yǔ)言中一個(gè)指針被定義后沒(méi)有分配到任何變量時(shí),它的值為nil。
2、new函數(shù)
在 Go 語(yǔ)言中,new 函數(shù)用于動(dòng)態(tài)地分配內(nèi)存,返回一個(gè)指向新分配的零值的指針。它的語(yǔ)法如下:
func new(Type) *Type
其中,Type 表示要分配的內(nèi)存的類型,new 函數(shù)返回一個(gè)指向 Type 類型的新分配的零值的指針。但是需要注意的是,new 函數(shù)只分配內(nèi)存,并返回指向新分配的零值的指針,而不會(huì)初始化該內(nèi)存。
注意 1:用new(structName):這個(gè)方法得到的是*structName類型,即類的指針類型;用structName{init para}:這個(gè)方法得到的是structName類型,即類的實(shí)例類型,不是指針。
注意 2:new函數(shù)更多細(xì)節(jié)介紹請(qǐng)參見《Go語(yǔ)言new( )函數(shù)》這篇博文。
3、Golang指針隱式間接引用
Go 語(yǔ)言自帶指針隱式解引用 :對(duì)于一些復(fù)雜類型的指針, 如果要訪問(wèn)成員變量時(shí)候需要寫成類似*p.field的形式時(shí),只需要p.field即可訪問(wèn)相應(yīng)的成員。以下復(fù)雜類型自帶指針隱式解引用:
3.1 結(jié)構(gòu)體類型指針隱式間接引用
結(jié)構(gòu)體字段可以通過(guò)結(jié)構(gòu)體指針來(lái)訪問(wèn)。如果我們有一個(gè)指向結(jié)構(gòu)體的指針p,那么可以通過(guò)(*p).X來(lái)訪問(wèn)其字段X。不過(guò)這么寫太啰嗦了,所以語(yǔ)言也允許我們使用隱式間接引用,直接寫p.X就可以。示例代碼如下:
package main
import (
"fmt"
)
type Student struct {
name string
age int
weight float32
score []int
}
func main(){
pp := new(Student) //使用 new 關(guān)鍵字創(chuàng)建一個(gè)指針
*pp = Student{"qishuangming", 23, 65.0, []int{2, 3, 6}}
fmt.Printf("stu pp have %d subjects\n", len((*pp).score)) //按照我們對(duì)指針的了解,對(duì)Student結(jié)構(gòu)體對(duì)象pp顯示賦值的話需要使用解引用語(yǔ)法進(jìn)行賦值,但是實(shí)際編碼時(shí)都會(huì)省去*,寫法如下行所示。
fmt.Printf("stu pp have %d subjects\n", len(pp.score)) //編譯器會(huì)自動(dòng)將指針解引用,并訪問(wèn)結(jié)構(gòu)體中的對(duì)應(yīng)字段,這個(gè)過(guò)程被稱為隱式間接引用。
}3.2 數(shù)組類型指針隱式間接引用
同樣指向數(shù)組的指針可以隱式解引用數(shù)組中的元素。
var arr [3]int p := &arr p[0] = 1 // 等價(jià)于 (*p)[0] = 1
3.3 切片類型指針隱式間接引用
切片實(shí)際上是對(duì)底層數(shù)組的封裝,因此指向切片的指針可以隱式解引用切片中的元素。
s := []int{1, 2, 3}
p := &s
p[0] = 4 // 等價(jià)于 (*p)[0] = 43.4 字典類型隱式間接引用
map 是引用類型,當(dāng)我們使用 map 類型的變量訪問(wèn)元素時(shí),也不需要使用 * 運(yùn)算符進(jìn)行解引用,Golang 會(huì)自動(dòng)幫我們解引用。
m := map[string]int{"a": 1, "b": 2}
fmt.Println(m["a"]) // 隱式解引用3.5func 類型隱式間接引用
在 Golang 中,函數(shù)類型也是一種類型,它可以使用指針類型來(lái)表示函數(shù)的地址。如果我們定義了一個(gè)函數(shù)類型的變量,并將一個(gè)函數(shù)的地址賦值給它,那么我們可以直接調(diào)用該變量,并且不需要使用 * 運(yùn)算符進(jìn)行解引用。
例如,以下代碼演示了函數(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)
}在上面的代碼中,我們定義了一個(gè)函數(shù)類型 Add,它接受兩個(gè) int 類型的參數(shù)并返回一個(gè) int 類型的值。我們定義了一個(gè)變量 add,它的類型是 Add。我們將一個(gè)函數(shù)的地址賦值給了 add 變量,然后直接調(diào)用了 add 變量,不需要使用 * 運(yùn)算符進(jìn)行解引用。
注意 1:函數(shù)類型指針的隱式解引用僅適用于函數(shù)類型變量的調(diào)用,而不適用于訪問(wèn)函數(shù)類型變量的成員。如果我們想要訪問(wèn)函數(shù)類型變量的成員,還是需要使用 * 運(yùn)算符進(jìn)行解引用。
注意 2:在 Go 中,基本類型(如 int、float、bool 等)以及字符串類型等非引用類型都沒(méi)有指針隱式解引用的行為。這意味著,如果需要訪問(wèn)基本類型的指針指向的值,必須顯式地使用 * 運(yùn)算符來(lái)解引用指針。下面是一個(gè)示例:
var i int p := &i *p = 1 // 顯式解引用指針來(lái)修改指針?biāo)赶虻闹? fmt.Println(i) // 輸出 1
另外,對(duì)于基本類型而言,使用指針可能會(huì)導(dǎo)致性能下降。因此,在使用指針時(shí)應(yīng)該謹(jǐn)慎,并且只在必要的情況下使用指針來(lái)傳遞數(shù)據(jù)?! ?/p>
4、總結(jié)
在 Go 中,指針隱式解引用是指通過(guò)指針直接訪問(wèn)指針?biāo)赶虻闹?,而不需要顯式地使用 * 運(yùn)算符來(lái)解引用指針。對(duì)于一些復(fù)雜類型的指針(結(jié)構(gòu)體類型指針、數(shù)組/切片類型指針、字典類型、func類型), 如果要訪問(wèn)成員變量時(shí)候需要寫成類似*p.field的形式時(shí),只需要p.field即可訪問(wèn)相應(yīng)的成員。
到此這篇關(guān)于Golang指針隱式間接引用的文章就介紹到這了,更多相關(guān)Golang指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言異常處理(Panic和recovering)用法詳解
異常處理是程序健壯性的關(guān)鍵,往往開發(fā)人員的開發(fā)經(jīng)驗(yàn)的多少?gòu)漠惓2糠痔幚砩暇湍艿玫襟w現(xiàn)。Go語(yǔ)言中沒(méi)有Try?Catch?Exception機(jī)制,但是提供了panic-and-recover機(jī)制,本文就來(lái)詳細(xì)講講他們的用法2022-07-07
Golang defer延遲語(yǔ)句的實(shí)現(xiàn)
defer擁有注冊(cè)延遲調(diào)用的機(jī)制,本文主要介紹了Golang defer延遲語(yǔ)句的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
一文搞懂Go語(yǔ)言中defer關(guān)鍵字的使用
defer是golang中用的比較多的一個(gè)關(guān)鍵字,也是go面試題里經(jīng)常出現(xiàn)的問(wèn)題。今天就來(lái)整理一下關(guān)于defer的學(xué)習(xí)使用,希望對(duì)需要的朋友有所幫助2022-09-09
使用Go語(yǔ)言連接和操作數(shù)據(jù)庫(kù)的基本步驟
在Go語(yǔ)言中,連接和操作數(shù)據(jù)庫(kù)通常使用database/sql包,它提供了一個(gè)數(shù)據(jù)庫(kù)抽象層,支持多種數(shù)據(jù)庫(kù)引擎,如MySQL、PostgreSQL、SQLite等,下面我將以MySQL為例,詳細(xì)講解如何使用Go語(yǔ)言連接和操作數(shù)據(jù)庫(kù),需要的朋友可以參考下2024-06-06

