關於值傳遞和引用傳遞的解釋

董雷發表於2021-12-30

值傳遞

值傳遞的資料型別

基本型別

基本型別是Go語言自帶的型別,比如數值型別、浮點型別、字元型別以及布林型別,他們本質上是原始型別,也就是不可改變的,所以對他們進行操作,一般都會返回一個新建立的值,所以把這些值傳遞給函式時,其實傳遞的是一個值的副本。

func changeDate(name string) string{
    name = name+"你的資料被改變了"
    return name
}
func main() {
    name:="董雷"
    tmpName := changeDate(name)
    fmt.Println(name)
    fmt.Println(tmpName)
}
//返回結果
董雷
董雷你的資料被改變了

上面的案例name在changeDate方法中修改了值,但是並沒有影響main中的name,也就是說,我們傳遞的時一個副本,並且返回一個新建立的字串。

基本型別因為是拷貝的值,並且在對他進行操作的時候,生成的也是新建立的值(寫時複製機制),所以這些型別在多執行緒裡是安全的,我們不用擔心一個執行緒的修改影響了另外一個執行緒的資料。

引用傳遞

引用型別和原始的基本型別恰恰相反,它的修改可以影響到任何引用到它的變數

引用型別有

  • 切片、[]string
  • map、mapp[string]string
  • 介面、interface{}
  • 函式型別、
  • 管道(chan)

引用型別之所以可以引用,是因為我們建立引用型別的變數,其實是一個標頭值,標頭值裡包含一個指標,指向底層的資料結構,當我們在函式中傳遞引用型別時,其實傳遞的是這個標頭值的副本,它所指向的底層結構並沒有被複制傳遞,這也是引用型別傳遞高效的原因。

案例

func changeDate(slice []string) []string {
    slice[0] = "你的企片被改了"
    return slice
}
func main() {
    slice := []string{"我是切片"}
    tmpSlice := changeDate(slice)
    fmt.Println(slice)
    fmt.Println(tmpSlice)
}
//返回結果
[你的企片被改了]
[你的企片被改了]

可以看到切片在函式裡面修改了,main裡面的變數也會一起被修改,所以是引用傳遞

結構型別

結構體是值傳遞,會複製一個新值,包括下面的子元素不管是什麼型別都會被影響

如何實現引用傳遞 &結構體 這種方式

程式碼

type person struct {
    age int
    name []string
    point *map[string]string
}
func modify(p person) {
    p.age =p.age+10
    p.name = []string{"王子"}
    p.point = &map[string]string{"name":"李四"}
}
func main() {
    tmpMap := make(map[string]string)
    tmpMap["name"] = "站桑"
    donglei := person{10,[]string{"董雷"},&tmpMap}
    fmt.Println(donglei)
    modify(donglei)
    fmt.Println(donglei)
}
//返回結果
{10 董雷}
{10 董雷}

自定義型別

自定義型別的好處,最主要的就是就是可以對自定義型別新增方法

本作品採用《CC 協議》,轉載必須註明作者和本文連結
good good study day day up

相關文章