Golang仿函式實現方法及效率測試
阿新 • • 發佈:2018-11-23
在C++ STL中,仿函式(functors)被大量用作改變演算法的內在行為。
由於Golang不支援泛型,所以沒法像C++那樣靈活的使用仿函式。但是Golang有interface,函式是”一等公民”(可賦值給指定型別變數),因此,在Golang中實際上也可以像仿函式那樣,通過具有相同引數和返回值的方法宣告的不同物件,實現行為的差異化。
下面,詳細講述,Golang中的實現方法:
以下通過不同方法實現 Lesser(int,int)bool 和 Greater(int,int)bool的不同行為舉例。
1. 通過interface實現
type Comparer interface {
F(left, right int) bool
}
//create cmp object by name
func CreateComparer(cmpName string) (r Comparer) {
switch cmpName {
case "": //default Lesser
fallthrough
case "Lesser":
r = Lesser{}
case "Greater":
r = Greater{}
default: //unsupport name
panic (cmpName)
}
return
}
//Lesser
type Lesser struct{}
func (this Lesser) F(left, right int) (ok bool) {
ok = left < right
return
}
//Greater
type Greater struct{}
func (this Greater) F(left, right int) (ok bool) {
ok = right < left
return
}
2.通過函式物件實現
type CmpFunc func (left, right int) bool
//create cmp object by name
func GetCmpFunc(cmpName string) (r CmpFunc) {
switch cmpName {
case "": //default Lesser
fallthrough
case "Lesser":
r = Less
case "Greater":
r = Great
default: //unsupport name
panic(cmpName)
}
return
}
//Lesser
func Less(left, right int) (ok bool) {
ok = left < right
return
}
//Greater
func Great(left, right int) (ok bool) {
ok = right < left
return
}
3.通過轉調物件實現
type CmpObj byte
const (
CMP_LESS CmpObj = iota
CMP_GREAT
)
func (me CmpObj) F(left, right int) (ok bool) {
switch me {
case CMP_LESS:
ok = Less(left, right)
case CMP_GREAT:
ok = Great(left, right)
default:
panic(me)
}
return
}
以下是3種方法的效率測試:
var (
cmp1 = CreateComparer("Lesser")
cmp2 = GetCmpFunc("Lesser")
cmp3 = CMP_LESS
N = 100000000
)
func TestSize(t *testing.T) {
fmt.Println("Interface", unsafe.Sizeof(cmp1))
fmt.Println("Func", unsafe.Sizeof(cmp2))
fmt.Println("Obj", unsafe.Sizeof(cmp3))
}
func Benchmark_Interface(b *testing.B) {
for i := 0; i < N; i++ {
cmp1.F(1, 2)
}
}
func Benchmark_Func(b *testing.B) {
for i := 0; i < N; i++ {
cmp2(1, 2)
}
}
func Benchmark_Obj(b *testing.B) {
for i := 0; i < N; i++ {
cmp3.F(1, 2)
}
}
//Interface 16
//Func 8
//Obj 1
//Benchmark_Interface-4 1000000000 0.55 ns/op
//Benchmark_Func-4 2000000000 0.19 ns/op
//Benchmark_Obj-4 2000000000 0.24 ns/op
結論如下:
用interface實現多型,會佔用兩個指標(16位元組空間) 執行效率上 大概慢一倍
使用函式指標 佔用1個指標(8位元組) 執行效率最高 但使用起來不夠靈活
使用轉調物件 只需要1個位元組 執行效率跟函式指標差不多
推薦使用第三種方法(轉調物件)的方法,使用數值列舉標識多路分發邏輯,效率上幾乎沒有損失,對外部引用物件的空間需求也比較小。
我將以上測試程式碼放在這裡,歡迎查閱:
https://github.com/vipally/glab/blob/master/lab5/lab5_test.go