由引用類型引發(fā)的概念的深入理解
我們從百度百科上面看引用的概念:引用類型 由類型的實際值引用(類似于指針)表示的數(shù)據(jù)類型。如果為某個變量分配一個引用類型,則該變量將引用(或“指向”)原始值。
這里是什么意思呢,意思是假如一個a變量是數(shù)組,這個數(shù)組的類型是引用類型,a有a[0]='111','111'保存在另外一個數(shù)據(jù)結(jié)構(gòu)b里面,這里的a[0]是指向的這個b數(shù)據(jù)的地址。
下面我們來通過例子理解一下。
package mainimport ("fmt")func main() {//這里是初始化聲明賦值一個a//a := []int{3, 4, 5}a := make([]int, 3)a[0] = 3a[1] = 4a[2] = 5test(a)fmt.Println(a)test2(a)fmt.Println(a)b := map[string]string{"a": "b",}test3(b)fmt.Println(b)test4(b)fmt.Println(b)}func test(a []int) {a[2] = 6}func test2(a []int) {//a = append(a, 9)a = []int{8, 93, 3, 11}fmt.Println("test2 a", a)}func test3(b map[string]string) {b["xx"] = "xxxx"}func test4(b map[string]string) {b = map[string]string{"888": "999",}}
下面我們看下結(jié)果:
第一次:[3 4 6] 這里是直接修改a的值,修改第二個值,打印是返回的值test2 a [8 93 3 11] 這里是在test2函數(shù)里面修改a的值,打印出來的第二次:[3?4?6]????這里是test2函數(shù)執(zhí)行之后返回的結(jié)果,a本身沒有變化,這里可以看出a本身不是引用的,但是a里面的值的變量是有引用的第一次:map[a:b xx:xxxx] 這里是map類型b的樣例,第一次是修改或者追加key和value,打印返回的值是修改成功的第二次:map[a:b xx:xxxx] 這里是第二次去本身函數(shù)改變,返回的b本身是不修改的,這里也同樣證明b本身不是引用的,b的值是有引用的好了,那么來了,如何對引用類型修改本身,那其實很簡單就是讓他們傳地址到函數(shù)中,在函數(shù)中修改,函數(shù)執(zhí)行完了,變量在函數(shù)中變化之后會在函數(shù)外也體現(xiàn)出來
下面我們看一下a slice的底層實現(xiàn)結(jié)構(gòu)體如下,如果我們直接使用它,它只有屬性array是指向一個地址的
type slice struct {array unsafe.Pointerlen intcap int}
順便我們了解下b map的底層實現(xiàn)結(jié)構(gòu)體是什么,其實我們存的值是在buckets里面,也是一個指針。
type hmap struct {// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.// Make sure this stays in sync with the compiler's definition.count int // # live cells == size of map. Must be first (used by len() builtin)flags uint8B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for detailshash0 uint32 // hash seedbuckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growingnevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)extra *mapextra // optional fields}
為了確定這個引用類型的知識點,我特意去用java寫了個例子,看看是不是語言通用的,java的本身底層函數(shù)實現(xiàn)我就沒有去了解了,后續(xù)有時間去嘗試。
import org.junit.Test;public class Application {@Testpublic void main() {String[] str = {"xxx", "bbb"};System.out.println("初始化數(shù)據(jù):"+str[1]);test(str);System.out.println("第一次:"+str[1]);test2(str);System.out.println("第二次:"+str[1]);}public void test(String[] str) {str[1] = "2";}public void test2(String[] str) {str = new String[]{"5", "6"};}}
下面是java的返回的結(jié)果
初始化數(shù)據(jù):bbb 初始化是bbb第一次:2 修改函數(shù)里面的值,返回的是修改的值第二次:2 這里是本str本身進行修改,修改完了之后,函數(shù)外之后執(zhí)行沒有變化。
好了,到這里我們對引用類型有了深入的理解了,后面有對底層slice和map的實現(xiàn)進行進一步了解和學(xué)習(xí)。
推薦閱讀
站長 polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場和創(chuàng)業(yè)經(jīng)驗
Go語言中文網(wǎng)
每天為你
分享 Go 知識
Go愛好者值得關(guān)注
評論
圖片
表情
