How to use function as map's key

huangapple go评论99阅读模式
英文:

How to use function as map's key

问题

如何将函数用作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

要将函数用作map的键,需要满足以下条件:

  1. 函数类型必须是可比较的类型,即函数类型必须支持相等性比较。
  2. 函数类型的参数和返回值类型必须是可比较的类型。

在上面的示例中,Action类型是一个函数类型,它的参数类型是int,返回值类型是空。由于空返回值类型不是可比较的类型,所以无法将Action类型用作map的键。要解决这个问题,可以修改Action类型的返回值类型为可比较的类型,或者考虑其他的键类型来代替函数类型。

英文:

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

得分: 13

你不能将函数用作映射键。语言规范明确指出:

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

英文:

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.

答案2

得分: 7

你不能在映射中使用函数作为键:键的类型必须是可比较的。

根据Go博客

映射的键可以是任何可比较的类型。语言规范对此有明确的定义,但简而言之,可比较的类型包括布尔、数值、字符串、指针、通道和接口类型,以及仅包含这些类型的结构体或数组。需要注意的是,切片、映射和函数不在此列表中;这些类型不能使用==进行比较,也不能用作映射的键。

根据你具体的用例,你可能会使用接口。

英文:

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.

答案3

得分: 7

你可以使用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)])
}
英文:

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)])
    }

答案4

得分: 6

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

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

点击此处查看代码。

英文:

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

答案5

得分: 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

答案6

得分: 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 根据函数指针返回唯一的 FunctionWrapper,使用 fnMap 避免为相同函数有多个值
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 // 这会覆盖之前的值,因为 fb 本质上与 fb2 相同

	fmt.Println(functions[fa])  // "true"
	fmt.Println(functions[fb])  // "false"
	fmt.Println(functions[fb2]) // "false"
}

这种方法有点繁琐,而且我认为将指针的字符串版本用作映射的键是一个非常糟糕的主意。但是...如果你真的需要的话,至少这是一个选项。

英文:

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.

答案7

得分: 2

一种简洁的方法是将函数包装在一个struct中,然后使用该结构的指针作为映射的键:

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
}

这样做可以实现你的需求。

英文:

A clean way to achieve this is to wrap the functions in a struct, then use a pointer to this struct as the map key:

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
}

答案8

得分: 1

使用函数指针作为映射键,而不是函数。

以下示例将函数的依赖关系存储在映射中,计算执行顺序并按正确顺序执行函数:

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()
}

希望对你有帮助!

英文:

Use function pointers as map keys instead of functions.

The following example stores dependencies of function in a map, calculates the execution order and executes the functions in the correct order:

package main
import (
&quot;fmt&quot;
)
type Action func()
var Premises = make(map[*Action][]*Action)
func OnSetup(action Action, premises ...*Action) *Action {
ap := &amp;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 &gt; 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 &lt; len(ranks); r++ {
fmt.Println(&quot;Rank:&quot;, r)
actions := ranks[r]
for a := range actions {
(*(actions[a]))()
}
}
}
func main() {
a := OnSetup(func() { fmt.Println(&quot;a&quot;) })
b := OnSetup(func() { fmt.Println(&quot;b&quot;) }, a)
OnSetup(func() { fmt.Println(&quot;c&quot;) }, b)
OnSetup(func() { fmt.Println(&quot;d&quot;) })
Setup()
}

huangapple
  • 本文由 发表于 2014年12月3日 16:38:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/27267042.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定