欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go中值傳遞和指針傳遞的使用

 更新時(shí)間:2024年10月16日 11:36:27   作者:-代號(hào)9527  
在Go語言中,使用&和*可以分別取得變量的地址和值,解引用未初始化或?yàn)閚il的指針會(huì)引發(fā)空指針異常,正確的做法是先進(jìn)行nil檢查,此外,nil在Go中用于多種類型的空值表示,值傳遞和指針傳遞各有適用場(chǎng)景,通常小型數(shù)據(jù)結(jié)構(gòu)優(yōu)先考慮值傳遞以減少解引用開銷

1、& 和 *

  • &后跟一個(gè)變量名,得到的是這個(gè)變量的內(nèi)存地址
  • *int類型的變量,代表這個(gè)變量里存的值是int類型的變量的內(nèi)存地址
  • 數(shù)據(jù)類型的指針類型,即在其前面加 * 號(hào)
  • 指針就是內(nèi)存地址
package main
import(
        "fmt"
)
func main(){

        var age int = 18
        //&符號(hào)+變量 就可以獲取這個(gè)變量內(nèi)存的地址
        fmt.Println(&age) //0xc0000a2058
        
        //ptr是一個(gè)變量,自身也有內(nèi)存地址
        //&age就是一個(gè)地址,是ptr變量的具體的值
        var ptr *int = &age

		//這樣直接輸出,是ptr這個(gè)指針變量的值,即0xc0000a2058
        fmt.Println(ptr)
        
        //ptr這個(gè)指針變量自身的地址
        fmt.Println("ptr本身這個(gè)存儲(chǔ)空間的地址為:",&ptr)
        
        //想獲取ptr這個(gè)指針或者這個(gè)地址指向的那個(gè)數(shù)據(jù):
        fmt.Printf("ptr指向的數(shù)值為:%v",*ptr) //ptr指向的數(shù)值為:18
}


在這里插入圖片描述

對(duì)指針類型的變量再加*,是取真實(shí)值,即解引用

x := 10
a := &x // 取變量x的地址,a是一個(gè)指向int的指針 (*int 類型)

fmt.Println(*a) // 輸出a指向的整數(shù)值,即變量x的值,這里將輸出 10

2、空指針

* 雖然可以取到指針類型的真實(shí)值(解引用),但對(duì)nil解引用,會(huì)空指針:panic: runtime error: invalid memory address or nil pointer dereference

比如以下情況:

聲明了一個(gè)指針變量,未初始化就直接解引用

var a *int
fmt.Println(*a)  // 這里將會(huì)導(dǎo)致空指針錯(cuò)誤

給一個(gè)指針變量賦值nil后解引用

var a *int = nil
fmt.Println(*a)  // 這里將會(huì)導(dǎo)致空指針錯(cuò)誤

調(diào)用了一個(gè)返回值是指針類型,但返回結(jié)果是nil的函數(shù)。此時(shí)直接解引用會(huì)空指針。

func returnNilPointer() *int {
    return nil
}

func main() {
    var a *int = returnNilPointer()
    fmt.Println(*a)  // 這里將會(huì)導(dǎo)致空指針錯(cuò)誤
}

對(duì)指針類型解引用的正確做法是,先判空:

var ptr *int

if ptr != nil {
    fmt.Println(*ptr)  // 安全地解引用ptr
} else {
    fmt.Println("Pointer is nil")
    // 避免解引用nil指針
}

3、nil

源碼:

在這里插入圖片描述

  • nil是go語言SDK中預(yù)先定義好的
  • 可以使用 == 操作符來比較指針、切片、映射、通道和接口變量是否為 nil
  • nil是指針、接口、切片、映射、通道和函數(shù)類型的空值
// 指針
var ptr *int
fmt.Println(ptr)  // 輸出: nil,即不指向任何有效的內(nèi)存地址
// 接口
var iface fmt.Stringer
fmt.Println(iface == nil)  // 輸出: true,即接口變量不指向任何具體的實(shí)現(xiàn)類對(duì)象
// 切片
var s []int
fmt.Println(s == nil)  // 輸出: true,即表示一個(gè)空切片,即長度和容量都為0的切片
// 映射
var m map[string]int
fmt.Println(m == nil)  // 輸出: true,表示一個(gè)空映射,即不包含任何鍵值對(duì)的映射
// 通道
var ch chan int
fmt.Println(ch == nil)  // 輸出: true,即未初始化的通道默認(rèn)為 nil
// 定義一個(gè)函數(shù)類型 HandlerFunc
type HandlerFunc func(int) string

// 聲明一個(gè) HandlerFunc 類型的變量 handler,但未賦值,其值為nil
 var handler HandlerFunc

因此,在未初始化的通道中發(fā)送或者接口數(shù)據(jù)、在未初始化的map中進(jìn)行存儲(chǔ)或者取值,就會(huì)panic,但切片有一點(diǎn)不同

var ch chan int
ch <- 1  // 嘗試向空通道發(fā)送數(shù)據(jù)會(huì)導(dǎo)致panic

報(bào)錯(cuò):

var m map[string]int
m["key"] = 1  // 嘗試在空映射中存儲(chǔ)值會(huì)導(dǎo)致panic

報(bào)錯(cuò):

只定義,未初始化的切片,其值為nil,表示一個(gè)空切片,即長度和容量都為0的切片,此時(shí),直接s[0] = 1就會(huì)發(fā)生下標(biāo)越界panic,但用append方法一切正常,append 函數(shù)會(huì)根據(jù)需要自動(dòng)初始化切片并分配內(nèi)存

var s []int
s[0] = 1	// 越界panic

在這里插入圖片描述

var s []int
s = append(s, 1)	// 不會(huì)panic或者空指針

注意,自定義的結(jié)構(gòu)體的空值不是nil,這一點(diǎn)和Java中的null不一樣(但如果加了&,即取地址,那就是自定義結(jié)構(gòu)體的指針類型,其空值為nil)

在這里插入圖片描述

此外,go中,所有的變量 (包括結(jié)構(gòu)體變量) 在聲明時(shí)如果沒有顯式賦值,會(huì)被賦予其類型的零值。比如:

在這里插入圖片描述

4、用值傳遞還是指針傳遞?

什么時(shí)候用值傳遞,什么時(shí)候用指針傳遞?比如向函數(shù)調(diào)用棧里的下一個(gè)方法傳遞對(duì)象A,二者的區(qū)別在于,指針傳遞,傳的是對(duì)象A的內(nèi)存地址,傳的是一個(gè)小巧的地址。值傳遞,是復(fù)制對(duì)象A的數(shù)據(jù)傳下去。

之前有個(gè)說法:想在調(diào)用的函數(shù)內(nèi)部改變對(duì)象A的值,就用指針傳遞,但這句話也不全對(duì),因?yàn)橛弥祩鬟f,照樣可以實(shí)現(xiàn)同樣的效果。比如對(duì)象A為:

// 矩形
type Rectangle struct {
	Width, Height int
}

此時(shí),要改變矩形的寬,值傳遞和引用傳遞(指針傳遞)的實(shí)現(xiàn)如下:

在這里插入圖片描述

注意看二者的返回值,值傳遞,因?yàn)椴荒苤苯有薷脑瓕?duì)象,因此,需要將副本對(duì)象整個(gè)都返回,引用傳遞,則是一個(gè)void方法,因?yàn)槠浣邮找粋€(gè)原對(duì)象的內(nèi)存地址,可以直接修改原對(duì)象。這兩種實(shí)現(xiàn)方式,在此時(shí),沒有誰優(yōu)誰劣。

考慮優(yōu)先使用值傳遞,原因如下:

  • 對(duì)于固定大小的類型(整數(shù)、浮點(diǎn)數(shù)、小型結(jié)構(gòu)體、小型數(shù)組),它們占用的內(nèi)存大小固定且小,大小與指針大小相當(dāng)

  • 值傳遞,代表的意志是:函數(shù)收到的是一個(gè)副本數(shù)據(jù),我只是需要操作這份數(shù)據(jù),不會(huì)改動(dòng)你的原始數(shù)據(jù)

在這里插入圖片描述

  • 對(duì)于較小的對(duì)象,直接值傳遞,可以避免引用傳遞時(shí)對(duì)指針解引用的額外步驟

此外,從底層分析原因:

在這里插入圖片描述

最后,如果傳遞的是一個(gè)很大的結(jié)構(gòu)體,那用指針傳遞更優(yōu)。

5、補(bǔ)充

關(guān)于使用指針類型的場(chǎng)景,還有:insert數(shù)據(jù)時(shí),數(shù)據(jù)庫中默認(rèn)值不對(duì)的時(shí)候:

在這里插入圖片描述

到此這篇關(guān)于go中值傳遞和指針傳遞的使用的文章就介紹到這了,更多相關(guān)go 值傳遞和指針傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang自定義開發(fā)Prometheus?exporter詳解

    Golang自定義開發(fā)Prometheus?exporter詳解

    Exporter是基于Prometheus實(shí)施的監(jiān)控系統(tǒng)中重要的組成部分,承擔(dān)數(shù)據(jù)指標(biāo)的采集工作,這篇文章主要為大家介紹了如何自定義編寫開發(fā)?Prometheus?exporter,感興趣的可以了解一下
    2023-06-06
  • golang如何使用struct的tag屬性的詳細(xì)介紹

    golang如何使用struct的tag屬性的詳細(xì)介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細(xì)介紹,從例子說起,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • Golang的Fork/Join實(shí)現(xiàn)代碼

    Golang的Fork/Join實(shí)現(xiàn)代碼

    Fork/Join本質(zhì)上是一種任務(wù)分解,將一個(gè)很大的任務(wù)分解成若干個(gè)小任務(wù),然后再對(duì)小任務(wù)進(jìn)一步分解,直到最小顆粒度,然后并發(fā)執(zhí)行,對(duì)Golang的Fork/Join實(shí)現(xiàn)代碼感興趣的朋友跟隨小編一起看看吧
    2023-01-01
  • Golang Goroutine的使用

    Golang Goroutine的使用

    這篇文章主要介紹了Golang Goroutine的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • golang之?dāng)?shù)據(jù)驗(yàn)證validator的實(shí)現(xiàn)

    golang之?dāng)?shù)據(jù)驗(yàn)證validator的實(shí)現(xiàn)

    這篇文章主要介紹了golang之?dāng)?shù)據(jù)驗(yàn)證validator的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 淺談Go語言中的結(jié)構(gòu)體struct & 接口Interface & 反射

    淺談Go語言中的結(jié)構(gòu)體struct & 接口Interface & 反射

    下面小編就為大家?guī)硪黄獪\談Go語言中的結(jié)構(gòu)體struct & 接口Interface & 反射。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • Go高級(jí)特性探究之對(duì)象比較詳解

    Go高級(jí)特性探究之對(duì)象比較詳解

    在go語言中,要比較兩個(gè)對(duì)象是否完全相同,我們可以使用三種方法,這篇文章主要為大家介紹了這三種方法的具體實(shí)現(xiàn),需要的可以參考一下
    2023-06-06
  • Golang并發(fā)編程深入分析

    Golang并發(fā)編程深入分析

    golang中的并發(fā),是函數(shù)相互獨(dú)立運(yùn)行的能力,goroutines是并發(fā)運(yùn)行的函數(shù)。golang提供了goroutines作為并發(fā)處理的一種方式
    2022-11-11
  • Golang二進(jìn)制文件混淆保護(hù)操作

    Golang二進(jìn)制文件混淆保護(hù)操作

    這篇文章主要介紹了Golang二進(jìn)制文件混淆保護(hù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • golang 自旋鎖的實(shí)現(xiàn)

    golang 自旋鎖的實(shí)現(xiàn)

    這篇文章主要介紹了golang 自旋鎖的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11

最新評(píng)論