方法是一種帶有特殊_接收者_引數的函式。
接收者會出現在自己的引數清單中,介於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