map with function pointer as key in go

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

map with function pointer as key in go

问题

我最近在我的golang项目中使用了一个包含函数指针作为键的映射,就像这样:

  1. map[*functiontype] somestructtype

我的一个同事说这是一个不好的主意,所以现在我对这个是否可行感到不确定。起初我认为这是可以的,因为方法指针可以进行相等性检查并且是不可变的。有人能提供一些关于这个问题的理由吗?

完整的示例代码如下:

  1. package main
  2. import "fmt"
  3. type s struct {
  4. string
  5. }
  6. type f func() string
  7. func func1() string { return "func 1" }
  8. func func2() string { return "func 2" }
  9. func main() {
  10. // 创建两个函数和两个指向它们的指针
  11. f1, f2 := func1, func2
  12. p1, p2 := (*f)(&f1), (*f)(&f2)
  13. // 创建一个函数指针的映射
  14. m := make(map[*f]s)
  15. m[p1] = s{"struct 1"}
  16. m[p2] = s{"struct 2"}
  17. // 打印映射
  18. printmapping(m, p1, p2)
  19. // 反转指针并打印
  20. p1, p2 = (*f)(&f2), (*f)(&f1)
  21. printmapping(m, p1, p2)
  22. }
  23. func printmapping(m map[*f]s, p1, p2 *f) {
  24. fmt.Println("pointer 1:", m[(*f)(p1)])
  25. fmt.Println("pointer 2:", m[(*f)(p2)])
  26. }
英文:

I recently used a map in one of my golang projects, that had function pointers as keys like this:

  1. map[*functiontype] somestructtype

One of my colleagues said this was a bad idea, so now I am unsure of this being feasible. I initially deemed it ok, because method pointers can be checked for equality and are immutable. Can someone provide some reasoning on that matter?

Complete example:

  1. package main
  2. import "fmt"
  3. type s struct {
  4. string
  5. }
  6. type f func() string
  7. func func1() string { return "func 1" }
  8. func func2() string { return "func 2" }
  9. func main() {
  10. // make two functions and two pointers to them
  11. f1, f2 := func1, func2
  12. p1, p2 := (*f)(&f1), (*f)(&f2)
  13. // make a map of their function pointers
  14. m := make(map[*f]s)
  15. m[p1] = s{"struct 1"}
  16. m[p2] = s{"struct 2"}
  17. // print out the mapping
  18. printmapping(m, p1, p2)
  19. // reverse the pointers and have that printed
  20. p1, p2 = (*f)(&f2), (*f)(&f1)
  21. printmapping(m, p1, p2)
  22. }
  23. func printmapping(m map[*f]s, p1, p2 *f) {
  24. fmt.Println("pointer 1:", m[(*f)(p1)])
  25. fmt.Println("pointer 2:", m[(*f)(p2)])
  26. }

答案1

得分: 6

如果键的类型是指向函数类型的指针(例如*func()),那么完全没问题,语义与预期一致:相等的指针是相等的键。

然而,查找映射中的值可能不会按照你的预期工作:示例。在这里,&f获取了局部变量的地址,对于AddFind的不同调用,这个地址是不同的。当然,下面的示例可能会有用:http://play.golang.org/p/F9jyUxzJhz

如果键的类型不是指针,那么这是一个坏主意,因为从Go 1开始就不可能实现。根据语言规范(在线演示):

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

由于比较函数的相等性是不可判定的问题,因此函数的==!=操作符是未定义的。

英文:

If the key type is a pointer to a function type (such as *func()) then it's totally fine and the semantics are as expected: equal pointers are equal keys.

However, looking up the values in the map may not work out as you may expect: example. Here &f takes the address of the local variable, which is never the same for different invocations of Add and Find. The following of course could be useful: http://play.golang.org/p/F9jyUxzJhz


If it is not a pointer, it's a bad idea because it's impossible from Go 1 onwards. According to the language specification (live demo):

> 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.

== and != aren't defined for functions since the problem of comparing functions for equality is undecidable.

答案2

得分: 4

你的问题太抽象了,没有实际意义。给我们一个真实例子的代码。如何创建一个最小、完整和可验证的示例。

例如,你是指像这样的代码吗?

  1. package main
  2. import "fmt"
  3. type f func(int) int
  4. type s struct{ i int }
  5. func f1(i int) int { return i }
  6. func f2(i int) int { return i * i }
  7. func main() {
  8. p1, p2 := f1, f2
  9. fmt.Println(p1, &p1, p2, &p2)
  10. m := make(map[*f]s)
  11. m[(*f)(&p1)] = s{f1(42)}
  12. m[(*f)(&p2)] = s{f2(42)}
  13. fmt.Println(m)
  14. p1, p2 = f2, f1
  15. fmt.Println(m)
  16. fmt.Println(p1, &p1, p2, &p2)
  17. }

输出:

  1. 0x20000 0x1040a120 0x20020 0x1040a128
  2. map[0x1040a120:{42} 0x1040a128:{1764}]
  3. map[0x1040a128:{1764} 0x1040a120:{42}]
  4. 0x20020 0x1040a120 0x20000 0x1040a128
英文:

Your question is too abstract to be meaningful. Give us code for a real example. How to create a Minimal, Complete, and Verifiable example..

For example, do you mean something like this?

  1. package main
  2. import "fmt"
  3. type f func(int) int
  4. type s struct{ i int }
  5. func f1(i int) int { return i }
  6. func f2(i int) int { return i * i }
  7. func main() {
  8. p1, p2 := f1, f2
  9. fmt.Println(p1, &p1, p2, &p2)
  10. m := make(map[*f]s)
  11. m[(*f)(&p1)] = s{f1(42)}
  12. m[(*f)(&p2)] = s{f2(42)}
  13. fmt.Println(m)
  14. p1, p2 = f2, f1
  15. fmt.Println(m)
  16. fmt.Println(p1, &p1, p2, &p2)
  17. }

Output:

  1. 0x20000 0x1040a120 0x20020 0x1040a128
  2. map[0x1040a120:{42} 0x1040a128:{1764}]
  3. map[0x1040a128:{1764} 0x1040a120:{42}]
  4. 0x20020 0x1040a120 0x20000 0x1040a128

huangapple
  • 本文由 发表于 2015年4月20日 20:32:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/29748003.html
匿名

发表评论

匿名网友

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

确定