参数类型 *T 副本创建 (按引用传递)
type Duck struct {
Age int
Name string
}
func passP(b *Duck) { //参数类型 *T 副本创建,修改原始变量的值
b.Age++
b.Name = "Great" + b.Name
fmt.Printf("传入修改后的Bird:\t %+v, \t内存地址:%p, 指针的内存地址: %p\n", *b, b, &b)
}
func main() {
parrot := &Duck{Age: 1, Name: "Blue"}
fmt.Printf("原始的Bird:\t\t %+v, \t\t内存地址:%p, 指针的内存地址: %p\n", *parrot, parrot, &parrot)
passP(parrot)
fmt.Printf("调用后原始的Bird:\t %+v, \t内存地址:%p, 指针的内存地址: %p\n", *parrot, parrot, &parrot)
}
/*
原始的Bird: {Age:1 Name:Blue}, 内存地址:0xc0000044c0, 指针的内存地址: 0xc000006028
传入修改后的Bird: {Age:2 Name:GreatBlue}, 内存地址:0xc0000044c0, 指针的内存地址: 0xc000006038
调用后原始的Bird: {Age:2 Name:GreatBlue}, 内存地址:0xc0000044c0, 指针的内存地址: 0xc000006028
*/
可以看到在 passP 中,在 T 类型作为参数的时候,传递的 parrot 参数会创建指针的副本(指针的内存地址: 0xc000006038)和原始变量的指针地址(指针的内存地址:0xc000006028),都指向同一个内存(实际)地址(0xc0000044c0)。显然,在函数内对 T 的改变会影响到原始变量的值,因为它是在同一个对象的操作。
如何选择 T 还是 *T
- 如果变量是数组或者结构体,使用类型 T 创建副本会影响性能,增加内存开销,可以使用指针类型 *T 传递
- 如果使用类型 T ,Golang 编译器则尽量将对象分配到栈上,而 *T 则可能被分配到对象上,会影响垃圾回收
- 如果不希望修改变量,就选择传递值类型 T ;如果希望修改原始变量的值,那么就选择指针类型 *T