2016-01-20 22 views
3

比如我的,我想比較的功能列表:如何比較Go中的2個函數?

http://play.golang.org/p/_rCys6rynf

type Action func(foo string) 

type Handler struct { 
    Get Action 
    Post Action 
} 

var routes map[string]Handler 

func Undefined(foo string) { 
} 

func Defined(foo string) { 
} 

func init() { 
    routes = map[string]Handler{ 
    `/`: Handler{Defined,Undefined}, 
    } 
} 

func main() { 
    for _, handler := range routes { 
    if handler.Post != Undefined { 
     // do something 
    } // invalid operation: (func(string))(handler.Post) != Undefined (func can only be compared to nil) 


    if &handler.Post != &Undefined { 
     // do something 
    } // cannot take the address of Undefined 
    // invalid operation: &handler.Post != &Undefined (mismatched types *Action and *func(string)) 
    } 
} 

什麼是比較,如果兩個功能是相同的正確方法?

+1

第一個錯誤信息很清楚。 [函數只能與'nil'](https://golang.org/ref/spec#Comparison_operators)相比。 –

+1

接口是否更清晰(並明顯解決問題)? –

回答

6

繼續之前:你應該重構,而不是比較函數值的地址。

Spec: Comparison operators:

切片,地圖,和函數值沒有可比性。然而,作爲特殊情況,片段,映射或函數值可以與預先標識的標識符nil進行比較。

函數值不具有可比性。你可以做的是比較函數值的地址是否相同(不是保存函數值的變量的地址,而是函數值本身)。

You can't take the address of a function,但如果您使用fmt包打印它,它會打印其地址。因此,您可以使用fmt.Sprintf()來獲取函數值的地址。

見這個例子中(根據您的代碼):

hand := &Handler{Undefined, Defined} 
p1 := fmt.Sprintf("%v", Undefined) 
p2 := fmt.Sprintf("%v", hand.Get) 
fmt.Println("Expecting true:", p1 == p2) 

fmt.Println("Expecting false:", fmt.Sprintf("%v", Defined) == fmt.Sprintf("%v", hand.Get)) 
fmt.Println("Expecting true:", fmt.Sprintf("%v", Defined) == fmt.Sprintf("%v", hand.Post)) 

輸出(嘗試在Go Playground):

Expecting true: true 
Expecting false: false 
Expecting true: true 

另一種選擇是使用reflect.Value.Pointer()得到的地址函數值,這正是fmt包的功能:fmt/print.go

func (p *pp) fmtPointer(value reflect.Value, verb rune) { 
    // ... 
    case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, 
      reflect.UnsafePointer: 
     u = value.Pointer() 
    // ... 
} 

但是你應該重構,而不是比較函數值地址。

+0

您可以詳細說明比較函數地址的缺陷嗎?另外,如果函數在內存中有地址,爲什麼它不能直接尋址?你能告訴我,在你看來,函數的字符串地址值是否可以接受[用於我的用例](http://stackoverflow.com/q/42140758/1375316)? – threeve

+0

@threeve在你的問題中回答:[集合中的唯一函數](http://stackoverflow.com/questions/42140758/collection-of-unique-functions-in-go/42147285#42147285) – icza

1

沒關係,找到了答案:

runtime.FuncForPC(reflect.ValueOf(handler.Post).Pointer()).Name() != 
    runtime.FuncForPC(reflect.ValueOf(Undefined).Pointer()).Name()