【问题标题】:What's the idiomatic way to use a struct containing a slice field as a map key in Go?在 Go 中使用包含切片字段的结构作为映射键的惯用方式是什么?
【发布时间】:2023-03-13 07:40:01
【问题描述】:

我有一个包含切片的结构,我想将其用作映射的键​​。我知道这是不允许的,因为目前尚未为 Go 中的切片定义相等性。我也知道我不能重写结构的相等性来手动进行切片比较。我的问题是:完成我在这里尝试做的最惯用的方法是什么?

这是一些使结构更清晰的示例代码:

package main

import "fmt"

type InternalStruct struct {
    item1, item2 bool
}

type ContainerStruct struct {
    internals []InternalStruct
}

func main() {
    container1 := ContainerStruct{}
    container1.internals = append(container1.internals, InternalStruct{item1: true})

    container2 := ContainerStruct{}
    container2.internals = append(container2.internals, InternalStruct{item1: true})

    m := make(map[ContainerStruct]int)
    m[container1] = 10

    fmt.Printf("container1 maps to: %d\n", m[container1])
    fmt.Printf("container1 maps to: %d\n", m[container2])
}

此代码无法编译(如预期的那样),但我正在寻找可以两次输出“10”的等效代码。实现此结果的最佳方法是什么?

【问题讨论】:

  • 也许使用哈希作为键?例如。 play.golang.org/p/zzvF2EVxrk 只会更好。基本上,在您的类型上创建一个方法,该方法返回可用作映射键的内容。
  • 感谢 Dave,这绝对是一个行之有效的解决方案。它看起来确实有点骇人听闻,但我不知道有什么更好的方法。
  • 链接代码中的 hack 仅在于密钥是如何生成的(我只是做了一些丑陋的演示)。您可以自己想办法为您自己的数据集为每个项目生成唯一的密钥。如果这不适合您,那么您需要寻找替代方案。

标签: dictionary struct go key slice


【解决方案1】:

您不能使用切片作为映射键,但如果您知道这些切片的大小,则可以使用数组代替。数组可以作为映射键。

package main

import "fmt"

func main() {
    m := make(map[[2]int]int)

    m[[2]int{1, 2}] = 3
    m[[2]int{3, 4}] = 1

    fmt.Println(m)
}

Playground

【讨论】:

  • 不幸的是,我在编译时不知道切片的大小,因此对于这种特定情况,这不是一个选项。
【解决方案2】:

即使您根据“相同的 ptr、cap 和 len”定义切片相等性,您想要的仍然无法工作,因为示例中的切片指向不同的底层内存,因此需要深入分析并破坏地图访问速度。

即使有一个名为 Hasher 的接口,您可以实现并使您的类型可映射,但您的示例仍然需要逐个元素检查、对结果哈希进行记忆,以及跟踪是否切片变了。我可能会建议你只使用 map[*ContainerStruct]int 并且只需处理这样一个事实,从概念上讲,您可能有两个不同的结构指针,它们的切片成员具有相同的数据。

考虑到这一切,我可能会建议先重新架构,如果做不到这一点,Dave C. 的上述建议,连同某种哈希值的记忆和一些跟踪何时需要重新架构的方法——计算出来的。

【讨论】:

    猜你喜欢
    • 2016-10-20
    • 1970-01-01
    • 2017-08-12
    • 2015-05-22
    • 1970-01-01
    • 2016-05-30
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    相关资源
    最近更新 更多