'How to create a unique key for a map

I'm creating a structure where a developer can store a reference to something and retrieve it when needed using a reference key, but not delete the reference.

How to create a unique key for a map that is generated at the point of insertion?

So far I'm using a not exported pointer to an empty *struct{} , but wondering if there there is a better way.

package main

import "fmt"

type referenceKey **struct{}

type reference[K referenceKey, R any] struct {
    s map[K]R
}

func (ref *reference[K, R]) Set(reference R) *K {
    if ref.s == nil {
        ref.s = make(map[K]R)
    }

    key := new(struct{})
    refKey := K(&key)
    ref.s[refKey] = reference

    return &refKey
}

func (ref *reference[K, R]) Get(key *K) R {
    return ref.s[*key]
}

func main() {
    ref := &reference[referenceKey, int]{}
    key1 := ref.Set(77)
    key2 := ref.Set(15345351)
    fmt.Println(ref.Get(key2))
    fmt.Println(ref.Get(key1))
}

https://go.dev/play/p/SF6S5BNlP7N

EDIT:

With int I have to keep a reference to it and increment it. To reduce code I tried to use the pointer to a instance of a empty struct.

Basically I need to create a unique key that can't be created outside internal package nor can Get method be called with an invalid key.

I've also fixed the code to now allow anyone to create a new invalid key.



Solution 1:[1]

Based on the comments I would make it with a counter and protect the store with a mutex for concurrent use:

package main

import (
    "fmt"
    "sync"
)

type reference[T any] struct {
    mutex   sync.RWMutex
    store   map[uint64]T
    counter uint64
}

func (r *reference[T]) Set(item T) uint64 {
    r.mutex.Lock()
    defer r.mutex.Unlock()
    if r.store == nil {
        r.store = make(map[uint64]T)
    }
    r.counter++
    r.store[r.counter] = item
    return r.counter
}

func (r *reference[T]) Get(key uint64) T {
    r.mutex.RLock()
    defer r.mutex.RUnlock()
    return r.store[key]
}

func main() {
    ref := reference[int]{}
    key1 := ref.Set(77)
    key2 := ref.Set(15345351)
    fmt.Println(ref.Get(key2))
    fmt.Println(ref.Get(key1))
}

But if in the future you need to be secure, and the keys should be random, then change the map's key to string, remove the counter and use uuid.NewString() for the new key value.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1