1 方法
Go没有类,但是可以为结构体类型定义方法。
方法就是一类带特殊的接收者参数的函数。
方法接收者在它自己的参数列表内,位于func关键字和方法名之间。
package main
import "fmt"
type sss struct{
aa, bb int
}
func (s sss) mmm() {
fmt.Println(s.aa, s.bb)
}
func main() {
ooo := sss{12, 34}
ooo.mmm()
}
note:方法mmm具有一个名为s类型为sss的接收者。
也可以为非结构体类型声明方法。
接收者的类型定义和方法声明必须在同一包内,不能为内置类型声明方法。
package main
import "fmt"
type iii int
func (i iii) fff() {
fmt.Println(i)
}
func main() {
i := iii(12)
i.fff()
}
2 方法即函数
方法本身就是一个正常的函数,功能并没有什么变化。
3 指针接收者
可以为指针类型的接收者声明方法,这意味着对于类型T,接收者类型可以使用文法T。(此外,T不能是类似于int这样的指针)
指针接收者的方法可以修改指针指向的值,由于方法经常需要修改它的接收者,所以指针类型的接收者比值类型的接收者更常用。
如果使用值接收者,方法会对原始接收者的副本进行操作。
package main
import "fmt"
type vvv struct {
xx, yy int
}
func (p *vvv) pf() {
p.xx = 111
p.yy = 111
}
func (v vvv) vf() {
v.xx = 111
v.yy = 222
}
func main() {
v := vvv{999, 999}
fmt.Println(v)
v.vf()
fmt.Println(v)
v.pf()
fmt.Println(v)
}
4 方法与指针重定向
带指针参数的函数必须接受一个指针,而以指针为接收者的方法被调用时,接收者既能为值又能为指针。
package main
import "fmt"
type vv struct{
x, y int
}
func (v *vv) sm(f int) {
v.x = v.x * f
v.y = v.y * f
}
func sf(v *vv, f int) {
v.x = v.x * f
v.y = v.y * f
}
func main() {
v := vv{3, 4}
v.sm(2)
sf(&v, 10)
fmt.Println(v)
p := vv{4, 3}
p.sm(3)
sf(p, 8)
fmt.Println(p)
}
相同的事情也发生在相反的方向。
接受值作为参数的函数必须接受指定类型的值,不能接收指针。
以值为接收者的方法被调用时,接收者既能为值又能为指针。
package main
import (
"fmt"
"math"
)
type vv struct{
x, y float64
}
func (v vv) abs() float64 {
return math.Sqrt(v.x*v.x + v.y*v.y)
}
func absf(v vv) float64 {
return math.Sqrt(v.x*v.x + v.y*v.y)
}
func main() {
v := vv{3, 4}
fmt.Println(v.abs())
fmt.Println(absf(v))
p := &vv{3, 4}
fmt.Println(v.abs())
fmt.Println(absf(*p))
}
5 选择值或指针作为接收者
使用指针接收者的原因有二:
首先,方法能够修改器接收者指向的值
其次,这样可以避免在每次调用方法时复制该值,提高效率
通常来说,所有给定类型的方法都应该有值或指针接收者,但是并不应该将二者混用。