Go语言 如何使用函数作为map的键

cbwuti44  于 2023-05-27  发布在  Go
关注(0)|答案(8)|浏览(228)

如何使用函数作为Map的关键?例如:

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

2w2cym1i

2w2cym1i1#

不能将函数用作Map键。语言规范明确指出:
比较运算符==和!=必须为键类型的操作数完全定义;因此,密钥类型不能是函数、Map或切片。

y53ybaqx

y53ybaqx2#

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

fafcakar3#

你不能在map中使用函数作为键:密钥类型必须是可比较的。
Go blog
Map键可以是任何可比较的类型。语言规范对此进行了精确的定义,但简而言之,类似的类型是布尔型、数值型、字符串型、指针型、通道型和接口型,以及只包含这些类型的结构或数组。值得注意的是,列表中没有切片、Map和函数;这些类型不能使用==进行比较,也不能用作Map键
根据您的具体用例,您可能使用的是一个接口。

hgncfbus

hgncfbus4#

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

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

64jmpszr

64jmpszr5#

函数不能是键:
比较运算符==和!=必须为键类型的操作数完全定义;因此,密钥类型不能是函数、Map或切片。
来源

6ss1mwsb

6ss1mwsb6#

你不能直接这样做,正如前面提到的,但是你可以假装你做了这样的事情:

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
这有点麻烦,老实说,我认为本质上使用指针的字符串版本作为Map的键是一个非常糟糕的主意。但如果你真的需要的话这至少是个选择

3df52oht

3df52oht7#

一种简单的方法是将函数 Package 在struct中,然后使用指向此结构体的指针作为map键:

type FuncPack struct {
    TheFunc func(a int)
}

func Test(a int)  {}
func Test2(a int) {}

func main() {
    theMap := make(map[*FuncPack]bool)
    theMap[&FuncPack{TheFunc: Test}] = true
    theMap[&FuncPack{TheFunc: Test2}] = false
}
e1xvtsh3

e1xvtsh38#

使用函数指针作为Map键而不是函数。
下面的示例将函数的依赖项存储在Map中,计算执行顺序并以正确的顺序执行函数:

package main

import (
    "fmt"
)

type Action func()

var Premises = make(map[*Action][]*Action)

func OnSetup(action Action, premises ...*Action) *Action {
    ap := &action
    Premises[ap] = premises
    return ap
}

func rank(action *Action) int {
    if len(Premises[action]) == 0 {
        return 0
    }
    max := 0
    for _, p := range Premises[action] {
        r := rank(p)
        if r > max {
            max = r
        }
    }
    return max + 1
}

func Setup() {
    ranks := make(map[int][]*Action)
    for action := range Premises {
        r := rank(action)
        ranks[r] = append(ranks[r], action)
    }
    for r := 0; r < len(ranks); r++ {
        fmt.Println("Rank:", r)
        actions := ranks[r]
        for a := range actions {
            (*(actions[a]))()
        }
    }
}

func main() {
    a := OnSetup(func() { fmt.Println("a") })
    b := OnSetup(func() { fmt.Println("b") }, a)
    OnSetup(func() { fmt.Println("c") }, b)
    OnSetup(func() { fmt.Println("d") })
    Setup()
}

相关问题