Golang如何使用函数作为map的键

时间:2014-12-03 08:38:48

标签: function map go key

如何将功能用作地图的关键?例如:

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 个答案:

答案 0 :(得分:12)

您不能将函数用作映射键。 language specification清楚地说:

  

必须为键类型的操作数完全定义比较运算符==和!=;因此,键类型不能是函数,映射或切片。

答案 1 :(得分:7)

您不能将功能用作地图中的键:键类型必须具有可比性。

来自Go blog

  

地图键可以是任何可比较的类型。语言规范   精确地定义了这个,但简而言之,可比较的类型是布尔值,   数字,字符串,指针,通道和接口类型,结构或   仅包含这些类型的数组。 明显缺席的是   切片,地图和功能;这些类型无法使用==进行比较,   并且不得用作地图密钥

根据您的确切用例,您可能会使用的是界面。

答案 2 :(得分:4)

功能不能是键:

  

必须为键类型的操作数完全定义比较运算符==和!=;因此,键类型不能是函数,映射或切片。

Source

答案 3 :(得分:3)

如前所述,你不能直接这样做,但你可以排序假装你做这样的事情:

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

这有点麻烦,老实说我认为将指针的字符串版本用作地图的关键字是一个非常糟糕的主意。但是......如果你真的需要它,它至少是一个选择。

答案 4 :(得分:3)

虽然函数不能是键,但函数指针可以。

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

答案 5 :(得分:3)

您可以使用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)])
    }