Golang как использовать функцию в качестве ключа карты

Как использовать функцию в качестве ключа карты? например:

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

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

этот код покажет ошибку:invalid map key type Action

6 ответов


можно использовать 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)])
    }

вы не можете использовать функцию в качестве ключа карты. The спецификация языка четко говорит:

операторы сравнения == и != должно быть полностью определено для операндов типа ключа; таким образом, тип ключа не должен быть функцией, картой или срезом.


вы не можете использовать функции в качестве ключей в картах : тип ключа должен быть сопоставимым.

с перейти в блог :

ключи карты могут быть любого сопоставимого типа. Спецификация языка определяет это точно, но, короче говоря, сопоставимые типы являются булевыми, числовые, строковые, указательные, канальные и интерфейсные типы, а также структуры или массивы, содержащие только эти типы. заметно отсутствуют в списке ломтики, карты и функции; эти типы нельзя сравнивать с помощью ==, и не может использоваться в качестве ключа карты

то, что вы можете использовать, в зависимости от вашего конкретного случая использования, является интерфейсом.


функции не могут быть кнопки:

операторы сравнения == и != должно быть полностью определено для операндов типа ключа; таким образом, тип ключа не должен быть функцией, картой или срезом.

источник


вы не можете сделать это напрямую, как уже говорилось, но вы можете вроде фейк это вы делаете что-то вроде этого:

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"
}

проверьте это на Go playground

Это немного громоздко, и я честно думаю, что очень плохая идея по существу использовать строковую версию указателя в качестве ключа вашей карты. Но... это, по крайней мере, вариант, если он вам действительно нужен.


в то время как функции не могут быть ключами, указатели функций могут.

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