go 方法
方法 method
方法的接收者是 struct
- go 没有类,但是可以为 struct 类型定义方法
- 方法是一类带特殊的“接收者”参数的函数
- 方法接收者在参数列表内,位于
func
关键字和方法名之间 - 接收者可以是命名类型或者结构体类型的个值或一个指针
- 所有给定类型的方法属于该类型的方法集
- 方法接收者在参数列表内,位于
语法格式
func (v_name v_type) func_name() [return_type] { //func body }
示例
package main import "fmt" type Circle struct { radius float64 } func (c Circle) getArea() float64 { return 3.14 * c.radius * c.radius } func main() { var c1 Circle c1.radius = 10.00 fmt.Println(c1.getArea()) }
方法的接收者是非结构体
也可以为非 struct 类型声明方法,定义作用于一个类型的方法
- 接收者的类型定义和方法声明必须在同一个包内,不能为内建类型声明方法
可为内置类型起一个别名,然后基于别名作为接收者定义方法
package main import ( "fmt" "math" ) type MyFloat float64 func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) } func main() { f := MyFloat(-math.Sqrt2) fmt.Println(f.Abs()) }
指针接收者 vs 值接收者
使用指针接收者
使用指针接收者,在方法内部修改会影响调用者
- 场景 1:希望方法内部修改影响调用者
场景 2:拷贝数据结构的代价比较大
package main import ( "fmt" "math" ) type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func (v *Vertex) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f } func main() { v := Vertex{3, 4} v.Scale(10) fmt.Println(v.Abs()) }
带指针参数的函数必须接受一个指针,而以指针为接收者的方法被调用时,接收者可以是值或者指针,go 会根据接收者类型自动调整
package main import ( "fmt" ) type vertex struct { X, Y float64 } func (v *vertex) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f } func scaleFunc(v *vertex, f float64) { v.X = v.X * f v.Y = v.Y * f } func main() { v := vertex{3, 4} v.Scale(2) scaleFunc(&v, 10) p := &vertex{4, 3} p.Scale(3) scaleFunc(p, 8) fmt.Println(v, p) }
使用值接收者
- 使用值接收者,类似于形参,方法内部的修改不影响调用者
- 接收一个值作为参数的函数必须接受一个指定类型的值,而以值作为接收者的方法被调用时,接收者可以是值或者指针
方法的匿名域
方法的接收者是一个结构体的匿名域(结构体中的结构体),可直接调用不指定匿名域
type address struct { city string state string } func (a address) fullAddress() { fmt.Println("Full address: %s, %s", a.city. a.state) } type person struct { firstName string lastName string address } func printPersonInfo(p person) { fmt.Println("name: %s %s", p.firstName, p.secondName) p.fullAddress()//p.address.fullAddress() }