Home  >  Article  >  Backend Development  >  Most efficient way to create unique map keys in Go

Most efficient way to create unique map keys in Go

WBOY
WBOYforward
2024-02-11 17:06:10497browse

在 Go 中创建唯一映射键的最有效方法

In the Go language, the most efficient way to create unique mapping keys has always been a concern for developers. When faced with scenarios where keys need to be unique, we need to find an efficient and reliable method. PHP editor Baicao will share in this article one of the most effective methods to help you create unique mapping keys in the Go language, making your code more optimized and efficient. Whether you are processing large-scale data or implementing highly concurrent applications, these methods can help you improve performance and efficiency. Let’s find out together!

Question content

I have a map[any]SomeType somewhere in the library. I want library users to be able to create keys for this map so that they are guaranteed not to conflict within a single application execution, and I want these keys to be efficient for map lookups.

The first thing that comes to mind is to use the memory address of a unique empty object. But everything I've tried so far has failed:

<code>package main

import "fmt"

var key1 = &struct{}{}
var key2 = &struct{}{}

var key3 = struct{}{}
var key4 = struct{}{}

var key5 = new(struct{})
var key6 = new(struct{})

func main() {
    fmt.Println("key1 == key2", key1 == key2)
    fmt.Println("key3 == key4", &key3 == &key4)
    fmt.Println("key5 == key6", key5 == key6)
    test(key1, key2, "func12")
    test(&key3, &key4, "func34")
    test(key5, key6, "func56")
}

func test(a, b any, msg string) {
    fmt.Println(msg, a == b)
}
</code>

Print

key1 == key2 true
key3 == key4 false
key5 == key6 true
func12 true
func34 true
func56 true

So getting the address of an empty structure variable is almost feasible until it is passed to a function. Then the difference disappears.

I don't want to introduce a key registry as it is an unnecessary complication. I also don't want to use strings, as different consumers of the library would need to negotiate keys or use namespaces, and the need to hash and compare strings is also an unnecessary complication.

Are there any methods that I haven't thought of?

Solution

The standard library uses a "trick" when using context.Context: the context can carry arbitrary values ​​in it, and these values ​​use interface{} Keying (any since a while) 1. Your own package can then define a new unexported type for the context keys it will use, and then define a set of constants with that type as context keys known to that package. Now the trick is that the type is always part of any value of type interface{}, so it is not possible to create an interface value that conflicts with the package's key.

Basically it’s like this:

package mypkg

type contextKey int

const (
  KeyFoo = contextKey(iota)
  KeyBar
)

Now, when you do key interface{} = KeyFoo, you are almost guaranteed that no other piece of code in your program can have the same value as key, because part of it will (Internal pointer to) Input contextKey is not exported. You may want to read this classic article to understand how it works (a little rusty, but still 99% correct)).

To me this looks like a way forward: users of your package can generate their own keys and submit them to your map, which map's key type should be interface {} or any. There is no need for a centralized registry to hand over these keys.

1 See context.Context.Value() and context.WithValue() for more information. The latter provides more tips on how to generate the key.

The above is the detailed content of Most efficient way to create unique map keys in Go. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete