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