Go 語言 方法值和方法表達式

2023-03-14 16:54 更新

原文鏈接:https://gopl-zh.github.io/ch6/ch6-04.html


6.4. 方法值和方法表達式

我們經(jīng)常選擇一個方法,并且在同一個表達式里執(zhí)行,比如常見的p.Distance()形式,實際上將其分成兩步來執(zhí)行也是可能的。p.Distance叫作“選擇器”,選擇器會返回一個方法“值”->一個將方法(Point.Distance)綁定到特定接收器變量的函數(shù)。這個函數(shù)可以不通過指定其接收器即可被調(diào)用;即調(diào)用時不需要指定接收器(譯注:因為已經(jīng)在前文中指定過了),只要傳入函數(shù)的參數(shù)即可:

p := Point{1, 2}
q := Point{4, 6}

distanceFromP := p.Distance        // method value
fmt.Println(distanceFromP(q))      // "5"
var origin Point                   // {0, 0}
fmt.Println(distanceFromP(origin)) // "2.23606797749979", sqrt(5)

scaleP := p.ScaleBy // method value
scaleP(2)           // p becomes (2, 4)
scaleP(3)           //      then (6, 12)
scaleP(10)          //      then (60, 120)

在一個包的API需要一個函數(shù)值、且調(diào)用方希望操作的是某一個綁定了對象的方法的話,方法“值”會非常實用(``=_=`真是繞)。舉例來說,下面例子中的time.AfterFunc這個函數(shù)的功能是在指定的延遲時間之后來執(zhí)行一個(譯注:另外的)函數(shù)。且這個函數(shù)操作的是一個Rocket對象r

type Rocket struct { /* ... */ }
func (r *Rocket) Launch() { /* ... */ }
r := new(Rocket)
time.AfterFunc(10 * time.Second, func() { r.Launch() })

直接用方法“值”傳入AfterFunc的話可以更為簡短:

time.AfterFunc(10 * time.Second, r.Launch)

譯注:省掉了上面那個例子里的匿名函數(shù)。

和方法“值”相關(guān)的還有方法表達式。當調(diào)用一個方法時,與調(diào)用一個普通的函數(shù)相比,我們必須要用選擇器(p.Distance)語法來指定方法的接收器。

當T是一個類型時,方法表達式可能會寫作T.f或者(*T).f,會返回一個函數(shù)“值”,這種函數(shù)會將其第一個參數(shù)用作接收器,所以可以用通常(譯注:不寫選擇器)的方式來對其進行調(diào)用:

p := Point{1, 2}
q := Point{4, 6}

distance := Point.Distance   // method expression
fmt.Println(distance(p, q))  // "5"
fmt.Printf("%T\n", distance) // "func(Point, Point) float64"

scale := (*Point).ScaleBy
scale(&p, 2)
fmt.Println(p)            // "{2 4}"
fmt.Printf("%T\n", scale) // "func(*Point, float64)"

// 譯注:這個Distance實際上是指定了Point對象為接收器的一個方法func (p Point) Distance(),
// 但通過Point.Distance得到的函數(shù)需要比實際的Distance方法多一個參數(shù),
// 即其需要用第一個額外參數(shù)指定接收器,后面排列Distance方法的參數(shù)。
// 看起來本書中函數(shù)和方法的區(qū)別是指有沒有接收器,而不像其他語言那樣是指有沒有返回值。

當你根據(jù)一個變量來決定調(diào)用同一個類型的哪個函數(shù)時,方法表達式就顯得很有用了。你可以根據(jù)選擇來調(diào)用接收器各不相同的方法。下面的例子,變量op代表Point類型的addition或者subtraction方法,Path.TranslateBy方法會為其Path數(shù)組中的每一個Point來調(diào)用對應(yīng)的方法:

type Point struct{ X, Y float64 }

func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }
func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }

type Path []Point

func (path Path) TranslateBy(offset Point, add bool) {
    var op func(p, q Point) Point
    if add {
        op = Point.Add
    } else {
        op = Point.Sub
    }
    for i := range path {
        // Call either path[i].Add(offset) or path[i].Sub(offset).
        path[i] = op(path[i], offset)
    }
}


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號