2014-12-03 31 views
6

Jak korzystać z funkcji jako klawisza mapy? na przykład:Golang, jak korzystać z funkcji jako klucza mapy

type Action func(int) 
func test(a int) { } 
func test2(a int) { } 

func main() { 
    x := map[Action]bool{} 
    x[test] = true 
    x[test2] = false 
} 

tych code by pokazać błąd: invalid map key type Action

+0

Jaki jest dokładny przypadek użycia? Czy interfejs nie byłby bardziej semantyczny i bardziej rozszerzalny? –

+0

Muszę wiedzieć, czy funkcja, którą otrzymałem od 'trie' jest funkcją, która została utworzona przez funkcję' X' lub nie. – Kokizzu

Odpowiedz

2

Nie można to zrobić bezpośrednio, jak już wspomniano, ale można rodzaju udawać zrobić coś takiego:

package main 

import "fmt" 

func a(i int) int { 
    return i + 1 
} 

func b(i int) int { 
    return i + 2 
} 

type Function func(int)int 
type FunctionWrapper struct { 
    f *Function 
} 

var fnMap = make(map[string]FunctionWrapper) 

// MakeFunctionWrapper returns a unique FunctionWrapper per Function pointer, using fnMap to avoid having multiple values for the same function 
func MakeFunctionWrapper(f Function) FunctionWrapper { 
    key := fmt.Sprintf("%#v", f) 
    data, ok := fnMap[key] 
    if !ok { 
     data = FunctionWrapper{&f} 
     fnMap[key] = data 
    } 
    return data 
} 

func main() { 
    functions := make(map[FunctionWrapper]bool) 
    fa := MakeFunctionWrapper(a) 
    fb := MakeFunctionWrapper(b) 
    fb2 := MakeFunctionWrapper(b) 
    functions[fa] = true 
    functions[fb] = true 
    functions[fb2] = false    // This overwrites the previous value since fb is essentially the same as fb2 

    fmt.Println(functions[fa])   // "true" 
    fmt.Println(functions[fb])   // "false" 
    fmt.Println(functions[fb2])   // "false" 
} 

Check it out on the Go playground

Jest to nieco kłopotliwe i szczerze mówiąc uważam, że bardzo zły jest zasadniczo użycie jako wskaźnika twojej mapy wersji smyczkowej wskaźnika. Ale ... to przynajmniej opcja, jeśli naprawdę tego potrzebujesz.

+0

Działa to tylko tak długo, jak długo zachowujesz swoje otoczenie funkcji i zawsze używasz ich ponownie . Tworzenie 2 owijek wokół tej samej funkcji nie daje takiego samego wyniku: http://play.golang.org/p/DdwzCTORBf – chakrit

+1

To nie jest dobre ... Zaktualizuję moją odpowiedź. – Nerdmaster

11

Nie można używać funkcji jako klucz mapy. language specification wyraźnie mówi:

The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice.

7

Nie można używać funkcji jako klucze w mapach: klucz typu muszą być porównywalne.

Od Go blog:

map keys may be of any type that is comparable. The language spec defines this precisely, but in short, comparable types are boolean, numeric, string, pointer, channel, and interface types, and structs or arrays that contain only those types. Notably absent from the list are slices, maps, and functions; these types cannot be compared using ==, and may not be used as map key

Co można użyć, w zależności od dokładnego przypadku użycia, to interfejs.

4

funkcje nie mogą być klawisze:

The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice.

Source

2

Chociaż funkcje nie mogą być klawiszami, wskaźniki funkcji mogą.

package main 

import "fmt" 

type strFunc *func() string 

func main() { 

    myFunc := func() string { return "bar" } 
    m := make(map[strFunc]string) 
    m[(strFunc)(&myFunc)] = "f" 

    for f, name := range m { 
     fmt.Println((*f)(), name) 
    } 
} 

http://play.golang.org/p/9DdhYduX7E

+0

Działa to tylko dlatego, że używasz adresu zmiennej, która nie jest taka sama jak "wskaźnik funkcji". Oto Twój przykład z tą samą funkcją przypisaną do innej zmiennej, a wynikowa mapa ma dwa wpisy, ponieważ adresy zmiennych są różne: https://play.golang.org/p/8DBIR4h1jU –