方法是一种带有特殊_接收者_实参的函数。
接收者出现在它自己的实参列表中,位于func关键字和方法名之间。
func (receiver type) MethodName(parameters) (returnTypes) {
}
只有当接收者的类型与方法定义在同一个包里时,你才能为它定义方法。
package person
type Person struct {
Name string
}
func (p Person) Greetings() string {
return fmt.Sprintf("Welcome %s!", p.Name)
}
结构体上的方法可以通过点号表示法调用。
p := Person{Name: "Bronson"}
fmt.Println(p.Greetings())
// Output: Welcome Bronson!
注意我们在Person实例p上调用方法Greetings()的方式。
这和在面向对象编程语言中调用方法的方式完全一样。
记住:方法只是一个带接收者实参的函数。 方法有助于避免命名冲突:因为方法绑定到特定的接收者类型,所以你可以在不同的类型上使用相同的方法名。
import "math"
type rect struct {
width, height int
}
func (r rect) area() int {
return r.width * r.height
}
type circle struct {
radius int
}
func (c circle) area() float64 {
return math.Pow(float64(c.radius), 2) * math.Pi
}
接收者有两种:值接收者和指针接收者。
到目前为止我们看到的所有方法都使用值接收者,这意味着它们收到的是传给方法的值的副本,也就是说,在方法内部对接收者所做的任何修改对调用方都不可见。
你可以用指针接收者来声明方法,以便修改接收者所指向的值。
做法是在类型名前面加一个*。
例如,对于rect类型,指针接收者会声明为*rect。
这类修改对方法的调用方也是可见的。
type rect struct {
width, height int
}
func (r *rect) squareIt() {
r.height = r.width
}
r := rect{width: 10, height: 20}
fmt.Printf("Width: %d, Height: %d\n", r.width, r.height)
// Output: Width: 10, Height: 20
r.squareIt()
fmt.Printf("Width: %d, Height: %d\n", r.width, r.height)
// Output: Width: 10, Height: 10
注意:本练习是 need-for-speed 练习的延续。
在本练习中,你将组织各种遥控车之间的比赛。每辆汽车都有自己的速度和耗电特性。
汽车一开始的电池是满的(100%)。 每次你使用遥控器驾驶汽车时,它会前进相当于车速的米数,同时剩余电量百分比会按其耗电量减少。
如果汽车的电池低于它的耗电百分比,你就不能再驾驶这辆汽车了。
遥控车有一个炫酷的 LED 显示屏,会显示两项信息:
"Driven <METERS> meters"。"Battery at <PERCENTAGE>%"。每条赛道都有自己的距离。 测试汽车的方式,是检查它们能否在不耗尽电池的情况下跑完赛道。
在Car上实现Drive方法,根据汽车的速度更新行驶的米数,并按照耗电量减少电池电量:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car.Drive()
// car is now Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}
注意:如果驾驶汽车会导致其电池低于 0,就不要尝试驾驶。
在Car上实现DisplayDistance方法,以string的形式返回 LED 显示屏上显示的距离:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
fmt.Println(car.DisplayDistance())
// Output: "Driven 0 meters"
在Car上实现DisplayBattery方法,以string的形式返回 LED 显示屏上显示的电池电量百分比:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
fmt.Println(car.DisplayBattery())
// Output: "Battery at 100%"
要跑完一场比赛,汽车必须能够行驶完赛道的距离。
也就是说,它不能在越过终点线之前耗尽电量。
实现CanFinish方法,该方法接收一个trackDistance int作为形参,如果汽车能跑完比赛就返回true,否则返回false:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
trackDistance := 100
car.CanFinish(trackDistance)
// => true