函數變量
函數作為變量值
函數變量是把函數作為值保存到變量中.
在Golang中,,函數也是一種類型,可以和其他類型一樣被保存在變量中.例如:
package main
// 將函數作為值保存到變量中
import (
"fmt"
)
func fire() {
fmt.Println("fire")
}
func main(){
f := fire() // 將變量f聲明為func()類型,此時f就被俗稱為“回調函數”, 此時f的值為nil
f()
}
我們經常選擇一個方法,並且在同一個表達式里執行,比如常見的p.Distance()形式,實際上將其分成兩步來執行也是可能的。
p.Distance叫作“選擇器”,選擇器會返回一個方法"值"->一個將方法(Point.Distance)綁定到特定接收器變量的函數。
這個函數可以不通過指定其接收器即可被調用;即調用時不需要指定接收器(譯注:因為已經在前文中指定過了),只要傳入函數的參數即可:
p := Point{1, 2}
q := Point{4, 6}
distanceFromP := p.Distance // method value
fmt.Println(distanceFromP(q))
當你根據一個變量來決定調用同一個類型的哪個函數時,方法表達式就顯得很有用了。你可以根據選擇來調用接收器各不相同的方法。
下面的例子,變量op代表Point類型的addition或者subtraction方法,Path.TranslateBy方法會為其Path數組中的每一個Point來調用對應的方法
package main
import "fmt"
type Point struct {
X, Y float64
}
func (p Point) Add(q Point) Point {
return Point{
X: p.X + q.X,
Y: 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 (p Path) TranslateBy(offset Point, add bool) Path {
var opration func(q, p Point) Point
if add {
opration = Point.Add
} else {
opration = Point.Sub
}
for i := range p {
p[i] = opration(p[i], offset)
}
return p
}
func main() {
// p := Point{1,1}
q := Point{2,2}
path := Path{{1,1}, {2,2}, {3,3}}
fmt.Printf("%#v\n", path.TranslateBy(q, true))
}
鏈式調用
鏈式調用
是一個泛概念,到底是什么東西的鏈式調用不明確。
函數的返回值是一個函數時,函數也能鏈式調用;
函數的返回值是一個對象時,直接調用返回值中對象的方法也是鏈式調用。
但是前者(1)顯然是沒有意義的。真正有意義的鏈式調用是后者(2),也就是方法鏈(method chaining)。方法鏈這個詞是有的,而且使用的很廣泛。其實很多人口中的
鏈式調用
實際上就是指方法鏈。但是鏈式調用
這個詞語還可以描述函數調用鏈,所以讓它自身的存在價值變得難以理解。鏈式調用的優點:
- 讓調用過程更接近自然語言。
- 把原本參數列表復雜的方法化作多個參數列表簡單的方法來使用。
- 減少不必要的代碼量。
在jQuery中很多東西就是使用了方法鏈的概念,那么在Golang中鏈式調用是怎么樣的呢?
實例 :字符串的鏈式處理
鏈式調用很好的體現了: 操作與數據分離的設計
字符串處理函數(StringProccess)需要外部提供數據源: 一個字符串切片(list []string), 另外還需要提供一個鏈式處理函數的切片(chain []func(string) string)
字符串鏈式處理設計思路:
- 這種處理函數能夠接受一個字符串輸入,處理后輸出
- strings.ToLower()函數能夠將傳入的字符串的每個字符變為小寫 func ToLower(s string) string
- 字符串處理函數StringProccess內部遍歷每個數據源提供的字符串,每個字符串都要經過一系列鏈式處理后重新返回切片
package main
import (
"fmt"
"strings"
)
// StringProccess 字符串處理函數,傳入字符串切片和處理鏈
func StringProccess(list []string, chain []func(string) string) {
// 遍歷每一個字符串
for index, str := range list {
// 第一個需要處理的字符串
result := str
// 遍歷每一個處理鏈
for _, proc := range chain {
// 輸入一個字符串進行處理,返回數據作為下一個處理鏈的輸入
result = proc(result)
}
// 將結果放回切片
list[index] = result
}
}
// 自定義處理函數
// 處理鏈函數即可以是系統提供的處理函數,也可以使用自定義的函數
// 自定義移除前綴的處理函數
func removePrefix(str string) string {
return strings.TrimPrefix(str, "go")
}
func main() {
// 提供待處理的字符串列表
list := []string{
"go scanner",
"go parser",
"go compiler",
"go printer",
"go formater",
}
// 處理函數鏈
chain := []func(string) string {
removePrefix,
strings.TrimSpace,
strings.ToUpper,
}
// 處理字符串
StringProccess(list, chain)
// 輸出處理好的字符串
for _, str := range list {
fmt.Printf(str)
}
}
總結
- 鏈式處理器是一種常見的編程設計.Netty是使用java語言編寫的一款異步事件驅動的網絡應用程序框架,
支持快速開發可維護的高性能的面向協議的服務器和客戶端,Netty中就有類似的鏈式處理器的設計. - 鏈式處理的開發思想將數據和操作拆分,解耦,讓開發者可以根據自己的技術優勢和需求,進行系統開發,同時將自己的開發成果共享給其他的開發