golang:方法接收者带星号和不带星号的区别
一,说明:
-
不带星号的方法:这些方法定义在值接收者(value receiver)上。
当你调用这些方法时,会操作该值的副本。
如果方法内部修改了接收者,这些修改不会反映到原始值上。 -
带星号的方法:这些方法定义在指针接收者(pointer receiver)上。
当你调用这些方法时,会操作原始值的指针。
如果方法内部修改了接收者指向的值,这些修改会反映到原始值上。
二,代码:
package main
import (
"fmt"
"reflect"
)
func isPointer(v interface{}) bool {
return reflect.ValueOf(v).Kind() == reflect.Ptr
}
// 定义一个结构体
type Person struct {
Name string
Age int
}
// 定义一个带星号的方法(指针接收者)
func (p *Person) IncrementAge() {
fmt.Printf("星号方法中 p是否指针: %v\n", isPointer(p))
fmt.Printf("星号方法中 p的地址:%p\n", &p)
fmt.Printf("星号方法中 p指向的地址:%p\n", &*p)
p.Age++
}
// 定义一个不带星号的方法(值接收者)
func (p Person) PrintAge() {
fmt.Printf("方法1中 p是否指针: %v\n", isPointer(p))
fmt.Printf("方法1中 p的地址:%p\n", &p)
fmt.Println("方法1改变前:",p.Age) // 输出:31
p.Age++ //此时的p是一个副本,修改后不会影响调用它的对象
fmt.Println("方法1改变后:",p.Age) // 输出:32
}
// 定义一个不带星号的方法2(值接收者)
func (p Person) PrintAge2() {
fmt.Printf("方法2中 p是否指针: %v\n", isPointer(p))
fmt.Printf("方法2中 p的地址:%p\n", &p)
fmt.Println("方法2改变前:",p.Age) // 输出:31
p.Age+=5 //此时的p是一个副本,修改后不会影响调用它的对象
fmt.Println("方法2改变后:",p.Age) // 输出:36
}
func main() {
person := Person{Name: "Alice", Age: 30}
fmt.Printf("person对象的地址:%p\n", &person)
fmt.Println("星号方法调用前:",person.Age) // 输出:31
person.IncrementAge() // 调用带星号方法
fmt.Println("星号方法调用后:",person.Age) // 输出:31
(&person).IncrementAge() // 调用带星号方法2
fmt.Println("星号方法调用后2:",person.Age) // 输出:31
person.PrintAge()
fmt.Println("person.Age:",person.Age) // 输出:31
person.PrintAge2()
fmt.Println("person.Age:",person.Age) // 输出:31
}
三,测试效果:
$ go run main.go
person对象的地址:0xc00009c000
星号方法调用前: 30
星号方法中 p是否指针: true
星号方法中 p的地址:0xc000088040
星号方法中 p指向的地址:0xc00009c000
星号方法调用后: 31
星号方法中 p是否指针: true
星号方法中 p的地址:0xc000088048
星号方法中 p指向的地址:0xc00009c000
星号方法调用后2: 32
方法1中 p是否指针: false
方法1中 p的地址:0xc00009c018
方法1改变前: 32
方法1改变后: 33
person.Age: 32
方法2中 p是否指针: false
方法2中 p的地址:0xc00009c030
方法2改变前: 32
方法2改变后: 37
person.Age: 32