go語言由引用類型引發的概念的深入理解

字號+ 編輯: 国内TP粉 修訂: 秃顶萧峰 來源: 利志分享 2023-09-12 我要說兩句(0)

360前技術總監曾哥編寫, 講述go語言引用類型的相關話題。

我們從百度百科上面看引用的概念:引用類型 由類型的實際值引用(類似於指針)表示的數據類型。如果爲某個變量分配一個引用類型,則該變量將引用(或“指向”)原始值。

這裡是什麽意思呢,意思是假如一個a變量是數組,這個數組的類型是引用類型,a有a[0]=’111’,’111’保存在另外一個數據結構b裡面,這裡的a[0]是指向的這個b數據的地址。

下面我們來通過例子理解一下。

import (
    "fmt"
)
func main() {
    // 這裡是初始化聲明賦值一個a
    // a := []int{3, 4, 5}
    a := make([]int, 3)
    a[0] = 3
    a[1] = 4
    a[2] = 5
    test(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",
    }
}

下面我們看下結果:

第一次:[3 4 6] 這裡是直接修改a的值,修改第二個值,列印是返回的值
test2 a [8 93 3 11] 這裡是在test2函數裡面修改a的值,列印出來的
第二次:[3 4 6] 這裡是test2函數執行之後返回的結果,a本身沒有變化,這裡可以看出a本身不是引用的,但是a裡面的值的變量是有引用的
第一次:map[a:b xx:xxxx] 這裡是map類型b的樣例,第一次是修改或者追加key和value,列印返回的值是修改成功的
第二次:map[a:b xx:xxxx] 這裡是第二次去本身函數改變,返回的b本身是不修改的,這裡也同樣证明b本身不是引用的,b的值是有引用的
好了,那麽來了,如何對引用類型修改本身,那其實很簡單就是讓他們傳地址到函數中,在函數中修改,函數執行完了,變量在函數中變化之後會在函數外也體現出來

下面我們看一下a slice的底層實現結構體如下,如果我們直接使用它,它只有屬性array是指向一個地址的

type slice struct { array unsafe.Pointer len int cap int}

順便我們了解下b map的底層實現結構體是什麽,其實我們存的值是在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 uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets 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 growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}

爲了確定這個引用類型的知識點,我特意去用java寫了個例子,看看是不是語言通用的,java的本身底層函數實現我就沒有去了解了,後續有時間去嘗試。

import org.junit.Test;
public class Application {
@Test
public void main() {
String[] str = {"xxx", "bbb"};
System.out.println("初始化數據:"+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的返回的結果

初始化數據:bbb 初始化是bbb
第一次:2 修改函數裡面的值,返回的是修改的值
第二次:2 這裡是本str本身進行修改,修改完了之後,函數外之後執行沒有變化。

好了,到這裡我們對引用類型有了深入的理解了,後面有對底層slice和map的實現進行進一步了解和學習。

閲完此文,您的感想如何?
  • 有用

    0

  • 沒用

    0

  • 開心

    0

  • 憤怒

    0

  • 可憐

    0

1.如文章侵犯了您的版權,請發郵件通知本站,該文章將在24小時内刪除;
2.本站標注原創的文章,轉發時煩請注明來源;
3.交流群: 2702237 13835667

相關課文
  • GO語言GORM如何更新字段

  • gorm如何創建記錄與模型定義需要注意什麽

  • gorm一般查詢與高級查詢

  • GORM時間戳跟蹤及CURD(增刪改查)

我要說說
網上賓友點評