Golang理解-函數變量


函數變量


函數作為變量值

函數變量是把函數作為值保存到變量中.

在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. 函數的返回值是一個對象時,直接調用返回值中對象的方法也是鏈式調用。

但是前者(1)顯然是沒有意義的。真正有意義的鏈式調用是后者(2),也就是方法鏈(method chaining)。方法鏈這個詞是有的,而且使用的很廣泛。其實很多人口中的鏈式調用實際上就是指方法鏈。但是鏈式調用這個詞語還可以描述函數調用鏈,所以讓它自身的存在價值變得難以理解。

鏈式調用的優點:

  1. 讓調用過程更接近自然語言。
  2. 把原本參數列表復雜的方法化作多個參數列表簡單的方法來使用。
  3. 減少不必要的代碼量。

上面引用至

在jQuery中很多東西就是使用了方法鏈的概念,那么在Golang中鏈式調用是怎么樣的呢?

實例 :字符串的鏈式處理

鏈式調用很好的體現了: 操作與數據分離的設計

字符串處理函數(StringProccess)需要外部提供數據源: 一個字符串切片(list []string), 另外還需要提供一個鏈式處理函數的切片(chain []func(string) string)

字符串鏈式處理設計思路:

  1. 這種處理函數能夠接受一個字符串輸入,處理后輸出
  2. strings.ToLower()函數能夠將傳入的字符串的每個字符變為小寫 func ToLower(s string) string
  3. 字符串處理函數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)
    }
}

總結


  1. 鏈式處理器是一種常見的編程設計.Netty是使用java語言編寫的一款異步事件驅動的網絡應用程序框架,
    支持快速開發可維護的高性能的面向協議的服務器和客戶端,Netty中就有類似的鏈式處理器的設計.
  2. 鏈式處理的開發思想將數據和操作拆分,解耦,讓開發者可以根據自己的技術優勢和需求,進行系統開發,同時將自己的開發成果共享給其他的開發


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM