Golang how to use function as map's key

2019-06-17 04:27发布

问题:

How to use function as map's key? for example:

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

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

those code would show an error: invalid map key type Action

回答1:

You can use reflect.

    import (
       "reflect"
       "math"
    )


    func foo () {
       table := make(map[uintptr] string)
       table[reflect.ValueOf(math.Sin)] = "Sin"
       table[reflect.ValueOf(math.Cos)] = "Cos"
       println(table[reflect.ValueOf(math.Cos)])
    }


回答2:

You cannot use a function as a map key. The language specification clearly says:

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.



回答3:

You can't use functions as keys in maps : the key type must be comparable.

From 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

What you might use, depending on your precise use case, is an interface.



回答4:

Functions cannot be keys:

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



回答5:

You cannot do this directly, as mentioned already, but you can sort of fake it you do something like this:

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

This is a bit cumbersome, and I honestly think it's a very bad idea to essentially use the string version of a pointer as your map's key. But ... it's at least an option if you really need it.



回答6:

While functions can't be keys, function pointers can.

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