2015-12-28 33 views
-1

我通過引用將一個結構傳遞給一個函數。爲什麼我通過的結構不變

我期待着如果我定義和更改函數內部的結構,我可以在外面獲得新的值。

但它沒有發生。

任何人都可以解釋爲什麼嗎?

package main 

import "fmt" 

func intbyRef(i *int) { 
    *i = 10 
} 

type ttt struct { 
    a int 
} 

func change(t *ttt) { 
    var p ttt = ttt{7} 
    fmt.Println(p) 
    t = &p 

} 

func main() { 

    i := 1 
    var t *ttt 

    fmt.Println(i) 
    fmt.Println(t) 

    change(t) 
    intbyRef(&i) 

    fmt.Println(i) 
    fmt.Println(t) 
} 

您可以嘗試在這裏的代碼:https://play.golang.org/p/I-GIdIZ9c6

+1

請考慮忘卻這個 「參照」 名不副實。在某些語言中,有*的區別:例如,在Python和PHP中,整數類型的值通過值傳遞,類類型的對象通過引用傳遞。相比之下,在Go中,所有值都通過值傳遞,只要您可以顯式傳遞指向值的指針即可,如果您希望被調用者修改指向的值,或者希望避免複製開銷。 – kostix

+1

考慮閱讀[this](http://stackoverflow.com/a/25354231/720999)和[this](http://stackoverflow.com/a/23551970/720999)。 – kostix

回答

0

在我們的代碼,你正在創建功能變化TTT的新對象,併爲其分配到t其作爲參數傳遞給函數。在go中,參數是按值傳遞的,所以當函數改變結束時,你賦值給t只是函數的作用域。爲了將更改傳播到調用函數返回值並將其分配回去。

所做的更改您的代碼,請打地面連桿 https://play.golang.org/p/S3GK0JLDHn

+0

謝謝,現在我明白了,所有的偶數指針都是作爲價值傳遞的。 –

1

你不改變函數內部的結構,你將其設置爲不同的內存地址更改值。換句話說,你並沒有改變存儲在t引用的地址上的對象,你改變的指針值爲t本身,它不會改變函數外的t變量的指針值(因爲Golang通過值)。

爲了做到你想要什麼,代碼應該類似於你在做什麼intbyRef,即:

func change(t *ttt) { 
    var p ttt = ttt{7} 
    fmt.Println(p) 
    *t = p 
} 

然而,這將與未繳指針引用恐慌。你的主要功能也應該做到你用INT做什麼:

func main() { 

    i := 1 
    // var t *ttt 
    t := new(ttt) 

    ... 
} 

下面的完整代碼(操場鏈接here):

package main 

import "fmt" 

func intbyRef(i *int) { 
    *i = 10 
} 

type ttt struct { 
    a int 
} 

func change(t *ttt) { 
    var p ttt = ttt{7} 
    fmt.Println(p) 
    // t = &p 
    *t = p 

} 

func main() { 

    i := 1 
    // var t *ttt 
    t := new(ttt) 

    fmt.Println(i) 
    fmt.Println(t) 

    change(t) 
    intbyRef(&i) 

    fmt.Println(i) 
    fmt.Println(t) 
} 

此外,您可能想在防範零值和返回錯誤,特別是對於你的包內部的函數。

+1

關於«一般來說,你應該防範零值和返回錯誤» - 請不要! [Here's](http://stackoverflow.com/a/22865084/720999)爲什麼。 – kostix

0

您正在通過初始化指針值爲intByRef並更改取消引用的值。

change您傳遞未初始化的指針值(又名nil)併爲其分配另一個指針。

所以你正在做兩件不同的事情。

您應該知道,當您將指針傳遞給函數時,會傳遞該指針的副本(指向相同的值)。這就是爲什麼maint在傳遞到change後沒有改變。它指向「舊」內存地址。

如果你想改變ttt指針傳遞給像你在intByRef做到這一點,你可以做到這一點的函數的值,但指針必須進行初始化(亦稱分配)。否則,你會嘗試解除零引用。

playground

func change(t *ttt) { 
    var p ttt = ttt{7} 
    fmt.Println(p) 
    *t = p 
} 

func main() { 
    t := new(ttt) 
    fmt.Println(t) 
    change(t) 
    fmt.Println(t) 
} 
相關問題