主要区分一下两个方面的内容:
- 单纯的方法定义
- 通过接口传递参数
1、 单纯的方法定义
go语言内部会自动进行值和指针的转换, 代码在编译的时候不会出错;区别在于使用指针定义方法,方法操作的是该数据本身;而使用值定义方法时,方法操作的是该数据的拷贝。
总结:如果使用除接口类型以外的类型作为接收者时,使用值和指针调用方法不会出现编译错误; 如果使用接口类型的变量(实现了该接口)调用方法时,使用值调用指针定义的方法时会出现编译出错。
1、 使用值定义方法,使用值调用方法的情况
type user struct {
name string
email string
}
func (u user) notify() {
//将传入的参数复制一份,赋值给u
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
输出(名子并不会改变):
Send email to Jack 1139329@163.com
{Andy 1139329@163.com}
2、 使用值定义方法,使用指针调用方法的情况
由于定义方法时使用的是值,在编译过程中会对调用者为指针的类型进行解引用,内部实现为 *user.notify()
type user struct {
name string
email string
}
func (u user) notify() {
//将传入的参数复制一份,赋值给u
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := &user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
输出(名子也不会改变):
Send email to Jack 1139329@163.com
{Andy 1139329@163.com}
3、 使用指针定义方法,使用指针调用方法的情况
type user struct {
name string
email string
}
func (u *user) notify() {
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
输出(名子会改变):
Send email to Jack 1139329@163.com
{Jack 1139329@163.com}
4、 使用指针定义方法,使用值调用方法的情况
内部实现为 *user.notify()
type user struct {
name string
email string
}
func (u *user) notify() {
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
输出(名子会改变):
Send email to Jack 1139329@163.com
{Jack 1139329@163.com}
2、 通过接口传递参数
1、 接受者receiver为值,使用值传递的情况
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//编译成功
2、 接受者receiver为值,使用指针传递的情况
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := &user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//编译成功
3、 接受者receiver为指针,使用指针传递的情况
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u *user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := &user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//编译成功
4、 接受者receiver为指针,使用值传递的情况
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u *user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//编译失败(使用指针接受者来实现一个接口,值类型无法实现对应的接口)
cannot use user (type user) as type notifyInterface in argument to sendNotification:
user does not implement notifyInterface (notify method has pointer receiver)
针对以上情况,《Go语言实战》一书中这样讲到,首先这是Go语言的一种规则,具体如下:如果使用指针接受者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。如果使用值接受者来实现一个接口,那么那个类型的值和指针都能够实现对应的接口。
为什么会有这样的限制呢:作者解释为go编译器并不总能自动获得一个值得地址!
网友评论
{“one”}是个值呀,是什么机制让它可以直接赋值给指针呢?
```
package main
type data struct {
A string
}
func main() {
_ = map[string]*data{"x": &data{"one"}}
}
```
使用gofmt工具,简化代码书写:
`gofmt -s -w main.go`
结果就是:
`_ = map[string]*data{"x": {"one"}}`