go 值傳遞和地址傳遞的例子

wubuze發表於2020-10-23

先來看個簡單的例子

1、變數前面加個&表示這個變數的地址(也就是這個變數的指標),指標變數前面加*表示這個指標對應的值 (自己理解下)

//main.go
package main
func ByAss() {
  s := 100
  p := &s  // s 的地址給了p

  fmt.Println(*p) //100 所以p對應的值變成了100
  *p += 100
  fmt.Println(*p)  //200
  fmt.Println(s) //200 p和s相同的地址,所以s也變成200
}

//demo.go
package main
func main() {
  ByAss()
}

Go 預設使用按值傳遞來傳遞引數,也就是傳遞引數的副本。函式接收引數副本之後,在使用變數的過程中可能對副本的值進行更改,但不會影響到原來的變數,比如 Function(arg1)。

2、普通值傳遞 (注意這個例子,看起來很簡單,但是容易忽略)

func ByValue1(n1 int) {
  //此時n1 是n 的一個拷貝,所以地址不一樣
  fmt.Println(&n1)//0xc00000a098
}

package main
func main() {
  n := 100
  fmt.Println(&n) //0xc00000a090
  ByValue1(n)//傳遞副本
}

如果你希望函式可以直接修改引數的值,而不是對引數的副本進行操作,你需要將引數的地址(變數名前面新增 & 符號,比如 &variable)傳遞給函式,這就是按引用傳遞,比如 Function(&arg1),此時傳遞給函式的是一個指標。

3、如果想用地址傳遞

func main() {
    n := 100
    fmt.Println(&n) //0xc00000a090
    ByReference(&n) //傳遞指標
    fmt.Println(n) //200
}

//注意函式 引數型別需要是用指標符號(*)
func ByReference(n1 *int) {

   *n1 += 100
   fmt.Println(n1)//0xc00000a090 地址與n相同, 所以n值被改變了
  //注意
  //ip := &n1//這個寫法有問題,表示地址的地址
  //fmt.Println(ip)
}

4、看下陣列

  • (a)陣列也是值傳遞
    arr := [5]int{1,3,5,6,7}
    arrByValue(&arr) //也需要使用& 符號
    fmt.Println(arr) //[100 300 5 6 7]
    func arrByValue(arr1 *[5]int) {
     arr2 := arr1
     arr2[0] = 100
     arr2[1] = 300
    }

5、下面是切片的例子 (可變的陣列)切片是引用傳遞

func main() {
    arr := []int{1,3,5,6,7}
    bbb(arr) //沒有使用& 符號
    fmt.Print(arr[0])// 11 結果已經改變,說明陣列是地址傳遞

    //就算不通過函式,也是引用傳遞
    //arr := []int{1,3,5,6,7}
    //arr2 := arr
    //arr2[1] = 0
    //fmt.Print(arr)//[1 0 5 6 7]
}
//aaa
func bbb(arr1 []int) {
   arr1[0] += 10
}
  • (b)在函式呼叫時,像切片(slice)、字典(map)、介面(interface)、通道(channel)這樣的引用型別都是預設使用引用傳遞(即使沒有顯式的指出指標)。

    6、aaa

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

相關文章