方法
方法是golang中的一个特性,方法可以看作是带有特殊接受者参数的函数,最常用的是为结构体定义方法,看起来就像面向对象里边的对象下的方法
package main
import (
"fmt"
)
type Book struct{}
func (b Book) SetPages() {
fmt.Println("SetPages")
}
func (b *Book) Pages() {
fmt.Println("Pages")
}
如示例,是为Book类型定义了SetPages方法、为*Book类型定义了Pages方法,既可以为指针定义方法,也可以为值类型定义方法,方法是带有特殊接收者参数的函数,所以上边定义与如下是相同的:
func Book.SetPages(b Book) {
fmt.Println("SetPages")
}
func (*Book).Pages() {
fmt.Println("Pages")
}
但是在定义时是不合法的,没法这么定义,但是我们可以显式调用隐式定义
func (b Book) SetPages() {
fmt.Println("SetPages")
}
func (b *Book) Pages() {
fmt.Println("Pages")
}
func main() {
var b Book
Book.SetPages(b) // 显式调用
(*Book).Pages(&b) // 显式调用
}
方法调用
调用方法时我们可以像面向对象调用对象下的方法一样,使用v.m
的形式
type Book struct{}
func (b Book) SetPages() {
fmt.Println("SetPages")
}
func (b *Book) Pages() {
fmt.Println("Pages")
}
func main() {
b := Book{}
b1 := &b
b.SetPages() // SetPages
b1.SetPages() // SetPages
b.Pages() // Pages
b1.Pages() // Pages
}
为什么可以使用指针调用SetPages方法、值类型调用Pages方法呢?并没有为指针定义SetPages方法,也没有为值定义Pages方法啊。
原因在于golang为了方便,在设计的时候有考虑到,实际在使用指针调用SetPages方法时,golang会将其解释为*b1.SetPages()
在使用值类型调用Pages方法时,golang会将其解释为&b.Pages()
坑
如果我们这样写呢?
func (b Book) SetPages() {
fmt.Println("SetPages")
}
func (b *Book) Pages() {
fmt.Println("Pages")
}
func main() {
(Book{}).SetPages() // SetPages
(&Book{}).SetPages() // SetPages
(&Book{}).Pages() // Pages
(Book{}).Pages() // 报错
}
会发现调用(Book{}).Pages()
会报错:
.\default.go:23:10: cannot call pointer method on Book literal
不能在字面量上调用指针方法,为什么不可以呢?和用变量调用的区别在哪呢?
原因
原因在于当接收者参数为指针类型时,接受者必须为可寻址的值类型,字面量结构体就是不可寻址的
func main() {
(Book{}).SetPages() // SetPages
(&Book{}).SetPages() // SetPages
(&Book{}).Pages() // Pages
fmt.Printf("地址为:%p\n", Book{})// 地址为:%!p(main.Book={})
}
返回值不是一个地址
在golang种具有&T{}
语法糖,与temp:=T{};(&temp)
相同,所以&T{}
可寻址不代表T{}
可寻址
参考资料
总结
以下情况可取地址操作
- 变量
- 可寻址的数组元素
- 可寻址的结构体字段
- 切片
- 指针引用