2014-12-03 32 views
6

Wie man Funktion als Schlüssel der Karte benutzt? zum Beispiel:Golang wie man Funktion als Schlüssel der Karte benutzt

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

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

diejenigen Code einen Fehler zeigen würde: invalid map key type Action

+0

Was ist die genaue Anwendungsfall? Wäre eine Schnittstelle hier nicht semantischer und erweiterbarer? –

+0

Ich muss wissen, ob eine Funktion, die ich von einem 'Trie 'erhielt, eine Funktion ist, die durch die Funktion' X' erzeugt wurde oder nicht. – Kokizzu

Antwort

2

Sie können dies nicht direkt tun, wie bereits erwähnt, aber man kann Art gefälschte es tun Sie etwas wie folgt aus:

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

Dies ist ein wenig umständlich, und ich denke, es ist eine sehr schlechte Idee, die String-Version eines Zeigers im Wesentlichen als Schlüssel Ihrer Karte zu verwenden. Aber ... es ist zumindest eine Option, wenn Sie es wirklich brauchen.

+0

Dies funktioniert nur so lange, wie Sie Ihre Funktions-Wrapper-Instanzen behalten und sie immer wieder verwenden . Erstellen von 2 Wrappern um die gleiche Funktion führen nicht zum gleichen Ergebnis: http://play.golang.org/p/DdwzCTORBf – chakrit

+1

Das ist nicht gut ... Ich werde meine Antwort aktualisieren. – Nerdmaster

11

Sie können keine Funktion als Kartenschlüssel verwenden. Die language specification klar sagt:

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

Sie keine Funktionen als Tasten in Karten verwenden können: der Schlüsseltyp vergleichbar sein müssen.

Von 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

Was Sie verwenden könnten, abhängig von Ihrem genauen Anwendungsfall ist eine Schnittstelle.

4

Funktionen können keine Schlüssel sein:

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

Während Funktionen keine Schlüssel sein können, können Funktionszeiger.

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

Dies funktioniert nur, weil Sie die Adresse einer Variablen verwenden, die nicht mit "Funktionszeiger" übereinstimmt. Hier ist Ihr Beispiel mit der gleichen Funktion, die einer anderen Variablen zugewiesen wurde, und die resultierende Karte hat zwei Einträge, da die Variablenadressen unterschiedlich sind: https://play.golang.org/p/8DBIR4h1jU –