指針傳遞與值傳遞
嚴格地說,go方法或函數(shù)只有一種傳遞方式伏恐,那就是值傳遞。每次將一個變量作為參數(shù)傳遞時熔恢,都會創(chuàng)建一個新的變量副本并將其傳遞給所調用的函數(shù)或方法脐湾。副本分配在不同的內存地址。
在指針傳遞變量的情況下叙淌,將創(chuàng)建指向相同內存地址的新副本秤掌。為了感受它們之間的差異,我們來看看它是如何工作的鹰霍。
值傳遞
package main
import "fmt"
type User struct {
name string
age int
}
func changeUser(u User) {
u.name = "李四"
u.age = 33
}
func main() {
user := User {
name: "張三",
age: 22,
}
changeUser(user)
fmt.Println(user)
}
接下來我們運行代碼闻鉴,得到的結果是 {張三 22}
請注意,即使changeUser 函數(shù)將u的name改為張三茂洒,age改為33.但是不會影響main函數(shù)里的user
因為u是user的值拷貝孟岛,內存地址并不相同。即user和u是兩個不同的User
指針傳遞
package main
import "fmt"
type User struct {
name string
age int
}
func changeUser(u *User) {
u.name = "李四"
u.age = 33
}
func main() {
user := User {
name: "張三",
age: 22,
}
changeUser(&user)
fmt.Println(user)
}
再次運行代碼,得到的結果是{李四 33}
發(fā)生這種情況是因為傳入changeUser函數(shù)的u是user的內存地址拷貝渠羞,即&user
u和&user指向的內存地址是一樣的斤贰,所以它們兩個是同一個User
何時使用值傳遞?何時使用指針傳遞次询?
- 變量是slice荧恍、map結構時使用值傳遞,因為slice和map本身就是引用類型
- 如果需要修改結構體屬性值屯吊,則必須使用指針
- 結構不大送巡,并且只讀情況下,盡量使用結構體盒卸。因為有逃逸分析
- 如果結構體占用內存較大骗爆,結構體作為參數(shù)傳遞時會發(fā)生拷貝影響性能,所以需要使用指針
在Go中值傳遞可能比指針傳遞開銷更小
發(fā)生這種情況是因為Go使用逃逸分析來確定變量是否可以安全地分配到函數(shù)的棧幀上蔽介,這可能比在堆上分配變量開銷小的多摘投。通過值傳遞可以簡化Go中的逃逸分析,并為變量提供更好的分配機會屉佳。