4 Go特種類型:值、指針、引用及nil

一、值、指針類型及引用類型

在Go中,一個變量持有的內(nèi)容無非三種:值類型、指針類型及引用類型。值類型和指針類型可以通過取值和取址操作互為轉(zhuǎn)換,而指針類型和引用類型,程序員們經(jīng)常會被這兩個相似的概念弄暈,別急,下面分別說明這些類型概念。

1.值類型

Go語言的值類型有以下幾種:

  • 基本數(shù)據(jù)類型(數(shù)值、布爾、字符、字節(jié))
  • 數(shù)組array
  • 結(jié)構(gòu)體struct(結(jié)構(gòu)體會在面向“對象”專題展開)

一個存儲值類型的變量,它在函數(shù)或方法的參數(shù)傳遞中是屬于拷貝傳遞的,即:傳遞的值類型參數(shù)在函數(shù)或方法內(nèi)部修改不會影響外部的變量數(shù)據(jù),而只會影響其拷貝的數(shù)據(jù)。

2.指針類型與內(nèi)存地址

上面我們提到值傳遞,在傳遞基本數(shù)據(jù)類型時,這種類型的變量只占1~8字節(jié),可以說非常廉價,對性能影響可以忽略不計。但在傳遞數(shù)組和結(jié)構(gòu)體時,如果數(shù)據(jù)體量較大,傳遞一個數(shù)組或結(jié)構(gòu)體代價是比較大的。
在開發(fā)中會遇到這種需求:一個變量傳遞給一個函數(shù)或方法,希望函數(shù)內(nèi)部對變量的修改可以影響外部,這時我們就需要把變量的內(nèi)存地址作為參數(shù)傳給函數(shù)或方法,這種傳地址的方式就是傳遞指針類型或引用類型(下面提到),可見指針的本質(zhì)就是內(nèi)存地址,一個指針類型的變量存放的就是指向源數(shù)據(jù)的內(nèi)存地址。

玩過C語言的都知道,指針是非常重要的概念,由于C語言中允許對指針進行運算,所以C中的指針操作有一定復(fù)雜度,對指針的管理特耗程序員心智,稍有不慎就會出錯。Go對指針進行精簡設(shè)計,只允許對指針進行取值和取地址操作,而且其最多支持二級指針,這大大簡化了程序員的使用難度,且不像C那樣容易出錯。只要熟悉指針的本質(zhì),一樣可以玩的溜!

一個值類型的變量都可以通過指針操作符獲取數(shù)據(jù)的內(nèi)存地址,而存放內(nèi)存地址的變量的類型就是指針類型。

var i = 1
iPtr := &i
ii := *iPtr

fmt.Printf("i的類型為%T,值為%v\n", i, i)
fmt.Printf("iPtr的類型為%T,值為%v\n", iPtr, iPtr)
fmt.Printf("ii的類型為%T,值為%v\n", ii, ii)


//i的類型為int,值為1
//iPtr的類型為*int,值為0xc000116048
//ii的類型為int,值為1

如上所見:i為存儲int數(shù)據(jù)的值類型變量,對i取地址后存到變量iPtr,iPtr為存儲指向int類型數(shù)據(jù)的指針,對iPtr指針類型取值后存到變量ii,ii為存儲int數(shù)據(jù)的值類型變量

在對普通變量使用&操作符取地址獲得這個變量的指針后,可以對指針使用*操作,也就是指針取值

  • &取址符可對任何變量使用,獲取變量地址
  • *指針取值符只可對指針變量使用

3.引用類型

所謂引用類型,我們可以把它們理解為一種go內(nèi)置的可占用一段內(nèi)存空間的數(shù)據(jù),其提供給用戶使用的是其占用內(nèi)存地址空間的頭部地址而非其存儲的數(shù)據(jù)本身,也就是說,它們天生就是指針類型,用戶不需要通過*指定指針類型聲明就可在調(diào)用中進行地址傳遞而非值傳遞。
Go內(nèi)置的引用類型為以下幾種:

  • 切片slice
  • 映射map
  • 函數(shù)func
  • 接口interface
  • nil

當你打印存有以上內(nèi)置類型的變量時,你會發(fā)現(xiàn)它們輸出的都是那段數(shù)據(jù)空間的頭部地址。由于存儲引用類型的變量是指針地址,所以其在傳遞過程性能較高,需要注意的是,傳遞引用類型時,函數(shù)或方法內(nèi)部對參數(shù)的修改會影響外部。

二、nil及零值

與其他語言一樣,Go語言也有指代空值的標識符:nil。但其又不是簡單含義的空值。Go官方說明了,nil是預(yù)定義的標識符,代表指針、通道、函數(shù)、接口、映射或切片的零值。簡單來說,nil實際上并不是指針,除基本值類型外,任何未分配內(nèi)存空間的變量聲明都指向nil,即零號內(nèi)存地址(0x0)。
例如:

var a []int = nil
fmt.Printf("a的類型為%T,地址為%p\n", a, a)
//a的類型為[]int,地址為0x0

說到零值,也順帶提一下go中內(nèi)置值類型的零值,基本值類型不能等于nil。

//不能通過編譯
//var a int = nil

//打印基本值類型的零值
var aa int
var bb bool
var cc float64
var dd [3]int
type St struct {
    a string
    b bool
    c int64
}
var st St

fmt.Printf("aa的類型為%T,值為:%v,地址為%p\n", aa, aa, &aa)
fmt.Printf("bb的類型為%T,值為:%v,地址為%p\n", bb, bb, &bb)
fmt.Printf("cc的類型為%T,值為:%v,地址為%p\n", cc, cc, &cc)
fmt.Printf("dd的類型為%T,值為:%v,地址為%p\n", dd, dd, &dd)
fmt.Printf("st的類型為%T,值為:%v,地址為%p\n", st, st, &st)

//aa的類型為int,值為:0,地址為0xc00008e018
//bb的類型為bool,值為:false,地址為0xc00008e020
//cc的類型為float64,值為:0,地址為0xc00008e028
//dd的類型為[3]int,值為:[0 0 0],地址為0xc000096020
//st的類型為base.St,值為:{ false 0},地址為0xc000088020

可見基本值類型聲明后就已經(jīng)分配內(nèi)存地址,并賦予零值。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,626評論 1 32
  • 一、用處 參考為什么要有指針?指針究竟是什么?是地址?還是類型?指針究竟有什么用? 1.變量一個東西在內(nèi)存里面,而...
    合肥黑閱讀 1,181評論 0 0
  • 第十章 指針 1. 地址指針的基本概念: 在計算機中,所有的數(shù)據(jù)都是存放在存儲器中的。一般把存儲器中的一個字節(jié)稱為...
    堅持到底v2閱讀 1,158評論 2 3
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 3,123評論 2 9
  • 我從小就崇拜老師,喜歡“老師”——這個太陽底下最光輝的職業(yè),夢想著有一天自己也成為這個崇高隊伍中的一員。 ...
    黑河027徐夢陽閱讀 422評論 0 0

友情鏈接更多精彩內(nèi)容