简体   繁体   中英

What's the idiomatic way to use a struct containing a slice field as a map key in Go?

I have a struct that contains a slice and I would like to use it as a key to a map. I understand that this is not allowed because equality is not currently defined for slices in Go. I also know that I can't override equality for the struct to do the slice comparison by hand. My question is: what is the most idiomatic way to accomplish what I'm trying to do here?

This is a bit of example code that makes the structure more clear:

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

This code doesn't compile (as expected), but I'm looking for something equivalent that would output "10" twice. What's the best way to go about achieving this result?

You cannot use slice as a map key, but if you know the size of such slices, you may use arrays instead. Arrays are allowed to be map keys.

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

Even if you defined slice equality in terms of "same ptr, cap and len", what you want still wouldn't work as the slices in your example point to different underlying memory, so a deep analysis would be necessary and ruin the speed of map access.

Even if there was an interface called Hasher that you could implement and make your type mappable, your example would still require an element-by element inspection, memoization of the resultant hash, and some method of tracking whether or not the slice had changed. I'd probably recommend you just use a map[*ContainerStruct]int and just deal with the fact that, conceptually, you might have two distinct structure pointers that have slice members with identical data.

Given all this, I'd probably recommend rearchitecting first, and, failing that, Dave C.'s suggestion above, along with some kind of memoization of the hash value and some way to track when it needs to be re-computed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM