英文:
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的键,需要满足以下条件:
- 函数类型必须是可比较的类型,即函数类型必须支持相等性比较。
- 函数类型的参数和返回值类型必须是可比较的类型。
在上面的示例中,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)
}
}
答案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.
答案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 (
"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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论