本文将详细讨论在Go语言中使用指针和值传递结构体的问题,以及他们的不同和需要注意的问题;
在开始前你需要先掌握结构体的定义、声明以及使用方法;
我们先来看一段代码:
package main
type T struct{
Value int
}
func main(){
myT := T{Value:666}
change(myT)
println(myT.Value)
}
func change(t T){
t.Value = 999
}
程序的输出是 666 ,因为这种方法传递的是值一个副本,在change() 函数中,你实际上修改的是副本的值;
修改程序,让它使用指针进行传递:
package main
type T struct{
Value int
}
func main(){
myT := T{Value:666}
change(&myT)
println(myT.Value)
}
func change(t *T){
t.Value = 999
}
这段程序使用了&取地址操作符来获取结构体的地址,而change()函数期望一个T结构体的地址类型 *T,这里*T的意思是指向类型T值得指针;
程序运行输出 999;
但我们需要注意的是,实际上这里传递的依然是一个副本,只不过这个副本是一个地址,它指向原来的值;
所以,你可以修改 t.Value的值,但你无法修改 t;
package main
type T struct{
Value int
}
func main(){
myT := T{Value:666}
change(&myT)
println(myT.Value)
}
func change(t *T){
t = &T{Value:999}
}
这段代码输出666;
那么,应该如何选择传递方式呢?
很明显,复制一个指针比复制一个结构的消耗要小的多;如果我们的结构非常复杂和庞大,那么复制结构会是一个很消耗性能的操作,在进行大量这样的操作时你的感觉会非常明显;
而使用指针则可避免这个问题;
当你的函数本意是改变原始数据时,那么肯定用指针转递;
当你的结构非常大时,比如包含庞大的切片、map时,也需要用指针转递;
但是如果你的结构体非常小,且不打算修改结构体内容,那么应该考虑使用值传递;
因为你不能保证程序没有bug导致误修改;且在某些多任务环境下,你需要为指针操作添加额外的锁操作,这样有些得不偿失。