天天看點

56.筆記go語言——go的函數類型匿名函數閉包函數收集函數作為域遞歸函數類型函數作為接口值作為Channel的函數友情連結

56.筆記go語言——go的函數類型

                  對于動态腳本語言Ruby,JavaScript,Python都有higher-order函數。但是很難直接轉換成G知識,雖然GO看上去是同樣方式擷取。另一方面,之前從事靜态語言特别是面向對象語言例如C++,JAVA的,那麼問題是使用higher-order函數很少。

                  很難直接從之前程式設計中直接跨越過來,是以蛤蟆也是需要學習,那麼和蛤蟆一起開始吧。

匿名函數閉包

                  Go語言支援匿名函數和閉包。

在GO中定義一個匿名函數非常簡單

func() {

    fmt.Println("hello")

}

                  不過這個很少用,通常是儲存到一個變量中,訂到資料結構中,或傳遞到其他函數。

                  通常常見的如下代碼:

fn :=func() {

    fmt.Println("hello")

}

                  這樣fn變量就是一個函數了,類型是func().當調用fn()的時候就會激活函數,或指派給其他感興趣的函數。當然,因為有閉包,可以引用在函數範圍中的一些資料。如下:

x := 5

fn :=func() {

    fmt.Println("x is", x)

}

fn()

x++

fn()

輸出

X is 5

X is 6       

函數收集

                  在使用資料類型的地方都可以使用函數,例如,可以建立slice函數組,随機選擇函數并執行。定義一個binFunc二進制函數,使用2個整型,傳回一個整型。那麼可以使用binFunc來替換func(int,int)int了。

                  代碼如下:

packagemain      
import"math/rand"      
import"time"      
import"fmt"      
typebinFuncfunc(int,int)int      
funcmain(){      
    //seedyourrandomnumbergenerator.      
    rand.Seed(time.Now().Unix())      
    //createasliceoffunctions      
    fns:=[]binFunc{      
        func(x,yint)int{returnx+y},      
        func(x,yint)int{returnx-y},      
        func(x,yint)int{returnx*y},      
        func(x,yint)int{returnx/y},      
        func(x,yint)int{returnx%y},      
    }      
    //pickoneofthosefunctionsatrandom      
    fn:=fns[rand.Intn(len(fns))]      
    //andexecuteit      
    x,y:=12,5      
    fmt.Println(fn(x,y))      
}      

執行結果:

17

當然是随機了。

函數作為域

                  通常,使用函數類型作為一個結構中的域。這樣可以讓我們給函數附加一些資訊,例如标簽等。

如下代碼:

packagemain      
import"math/rand"      
import"time"      
import"fmt"      
typeopstruct{      
    namestring      
    fn   func(int,int)int      
}      
funcmain(){      
    //seedyourrandomnumbergenerator      
    rand.Seed(time.Now().Unix())      
    //createasliceofops      
    ops:=[]op{      
        {"add",func(x,yint)int{returnx+y}},      
        {"sub",func(x,yint)int{returnx-y}},      
        {"mul",func(x,yint)int{returnx*y}},      
        {"div",func(x,yint)int{returnx/y}},      
        {"mod",func(x,yint)int{returnx%y}},      
    }      
    //pickoneofthoseopsatrandom      
    o:=ops[rand.Intn(len(ops))]      
    x,y:=12,5      
    fmt.Println(o.name,x,y)      
    fmt.Println(o.fn(x,y))      
}      

執行如下:

add 12 5

17

此外,函數還可以被存儲在maps中。

遞歸函數類型

                  另一個有意思的函數類型是允許定義遞歸函數類型。将自己類型作為參數或者使用自己的類型作為傳回值。

例如遞歸函數:

typewalkFn func(*int) walkFn

合法的walkFn可以如下walkEqual函數

func walkEqual(i*int) walkFn {

    *i += rand.Intn(7) - 3

    return walkEqual

}

函數傳回一個随機值并-3,然後傳回本身。

函數作為接口值

                  GO語言中的函數類型也可以有方法。很少見。

                  任何有方法的類型都可以滿足接口,是以函數類型可以來合法化接口類型。

                  GO中方法可以有指針或值接收。

                  PS:任何有Error() string方法的都是合法的error類型,函數可以作為或和error.

代碼如下:

packagemain      
import"fmt"      
typebinFuncfunc(int,int)int      
funcadd(x,yint)int{      
    returnx+y      
}      
func(fbinFunc)Error()string{      
    return"binFuncerror"      
}      
funcmain(){      
    varerrerror      
    err=binFunc(add)      
    fmt.Println(err)      
}      

在這個例子中,将add函數從func(int,int) int轉換為binFunc。

                  然後實作func(int,int) int的error.

再定義如下:

type loudBinFunc func(int, int) int      
func (f loudBinFunc) Error() string {      
    return "THIS ERROR IS A LOT LOUDER"      
}      

                  定義類型loudBinFunc,然後實作Error()函數。如果同時有 

binFunc

 和 

loudBinFunc

,那麼go就不知道如何轉換add函數了。一開始可能會反感,但是其實會讓我們避免代碼BUG。

在标準庫net/http包中,可以看到使用函數類型來滿足接口的例子。

作為Channel的函數

                  使用Channels來合并函數類型。

                  定義channel類型如下:

chan func()

                  建立函數組成的slice如下:

在定義一個函數來随機擷取,如下:

然後建立函數的channel.

在定義一個函數,将CHANNEL,數量描述,函數集作為參數,如下:

在函數開始處,使用了deferclose( c)來確定channel能得到關閉。

何在一起代碼如下:

執行輸出如下:

20

10

20

40

1600

3200

3201

6402

40985604

81971208

友情連結

http://jordanorelli.com/post/42369331748/function-types-in-go-golang