go的方法可分为方法值(method value),和方法表达式(method expression) 2种情况
准备工作
定义一个结构体,并且声明接收者方法
type User struct { id int name string } func (self User) Test() { fmt.Printf("%p,%v\\n", self, self) }
方法值
直接将方法声明赋值给新变量:
func main() { u := User{1, "tioncico"} u.Test() fun1 := u.Test u.name="tioncico2" fun1() u.Test() }
输出:
GOROOT=/Users/tioncico/sdk/go1.17 #gosetup GOPATH=/Users/tioncico/go/pkg/mod #gosetup /Users/tioncico/sdk/go1.17/bin/go build -o /private/var/folders/08/hkdkrdpn4mbb\_4l5zbvrq0hh0000gp/T/\_\_\_go\_build\_main_go /Users/tioncico/GolandProjects/LearnGoProject/main.go #gosetup /private/var/folders/08/hkdkrdpn4mbb\_4l5zbvrq0hh0000gp/T/\_\_\_go\_build\_main_go %!p(main.User={1 tioncico}),{1 tioncico} %!p(main.User={1 tioncico}),{1 tioncico} %!p(main.User={1 tioncico2}),{1 tioncico2}
可看出,方法值为值传递方式,更改name后,fun1的数值并没有更改
方法表达式
func main() { u := User{1, "tioncico"} u.Test() fun1 := (User).Test u.name="tioncico2" fun1(u) u.Test() }
输出:
GOROOT=/Users/tioncico/sdk/go1.17 #gosetup GOPATH=/Users/tioncico/go/pkg/mod #gosetup /Users/tioncico/sdk/go1.17/bin/go build -o /private/var/folders/08/hkdkrdpn4mbb\_4l5zbvrq0hh0000gp/T/\_\_\_go\_build\_main_go /Users/tioncico/GolandProjects/LearnGoProject/main.go #gosetup /private/var/folders/08/hkdkrdpn4mbb\_4l5zbvrq0hh0000gp/T/\_\_\_go\_build\_main_go %!p(main.User={1 tioncico}),{1 tioncico} %!p(main.User={1 tioncico2}),{1 tioncico2} %!p(main.User={1 tioncico2}),{1 tioncico2}
其实可以看出,方法值为 "具体实例的方法",已经存在具体实例,需要通过实例去调用接收者方法,所以不需要额外传入接收者
而方法表达式为:"结构体的方法",需要额外传入结构体进行实际调用
其他
package main import "fmt" type User struct { id int name string } func (self *User) Test() { fmt.Printf("%p,%v\\n", self, self) } func main() { var u *User=nil u.Test() //直接实例调用 (*User)(nil).Test() //方法值实例(实例值为nil)调用 (*User).Test(nil) //方法表达式,传入实例(实例为nil)调用 }