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.
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.
Related
In my code, I need a function that would return an ordered slice of keys from a map.
m1 := make(map[string]string)
m2 := make(map[string]int)
And now I need to call a function passing both types of maps:
keys1 := sortedKeys(m1)
keys2 := sortedKeys(m1)
Problem: I have to write two functions because the function should consume maps of two different types. At the same time, the body of the function will be the same in both cases.
Question: How can I use a single implementation for two maps? Or is there any other way of solving the problem in an elegant way?
My first idea was to use map[string]interface{} as an argument type, but you can't assign neither map[string]string, nor map[string]int to it.
My code:
func sortedKeys(m map[string]string) []string {
var keys []string
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
I would have to repeat the same code but for map[string]int.
You can use interface{} and use reflection for achieving this.
You can write two functions for the same but it is just not scalable, say, you are supporting string and int now but you wish to support int64, float64, bool or struct in the future. Having a common function using map[string]interface{} and using reflection is the way to go.
Suggested Code :
package main
import (
"fmt"
"reflect"
)
func main() {
m1 := make(map[string]string)
m2 := make(map[string]int)
m1["a"] = "b"
m1["b"] = "c"
m2["a"] = 1
m2["b"] = 2
fmt.Println(sortedKeys(m1))
fmt.Println(sortedKeys(m2))
}
// Returns slice of values in the type which is sent to it
func sortedKeys(m interface{}) interface{} {
if m == nil {
return nil
}
if reflect.TypeOf(m).Kind() != reflect.Map {
return nil
}
mapIter := reflect.ValueOf(m).MapRange()
mapVal := reflect.ValueOf(m).Interface()
typ := reflect.TypeOf(mapVal).Elem()
outputSlice := reflect.MakeSlice(reflect.SliceOf(typ), 0, 0)
for mapIter.Next() {
outputSlice = reflect.Append(outputSlice, mapIter.Value())
}
return outputSlice.Interface()
}
Output :
[b c]
[1 2]
https://play.golang.org/p/2fkpydH9idG
This question already has an answer here:
golang how can I use struct name as map key
(1 answer)
Closed 9 months ago.
We have a following function:
func (h *Handler) Handle(message interface{}) error {
//here there is a switch for different messages
switch m := message.(type) {
}
}
This signature is given and can't be changed. There are around 20 different message types the handler processes.
Now, there are some of these messages (around 4) which need special post-processing. In a different package.
Thus, I am thinking to do this like this:
func (h *Handler) Handle(message interface{}) error {
//here there is a switch for different messages
switch m := message.(type) {
}
//only post-process if original message processing succeeds
postProcessorPkg.Process(message)
}
Now, in the Process function, I want to quickly lookup if the message type is indeed of the ones we need postprocessing for. I don't want to do a switch again here. There are many handlers, in different packages, with varying amount of message types, and it should be generic.
So I was thinking of registering the message type in the postprocessor and then just do a lookup:
func (p *Postprocessor) Register(msgtype interface{}) {
registeredTypes[msgtype] = msgtype
}
and then
func (p *Postprocessor) Process(msgtype interface{}) error {
if ok := registeredTypes[msgtype]; !ok {
return errors.New("Unsupported message type")
}
prop := GetProp(registeredTypes[msgtype])
doSmthWithProp(prop)
}
This will all not work now because I can only "register" instances of the message, not the message type itself, as far as I know. Thus the map would only match a specific instance of a message, not its type, which is what I need.
So I guess this needs redesign. I can completely ditch the registering and the map lookup, but
I can't change the Handle function to a specific type (signature will need to remain message interface{}
I would like to avoid to have to use reflect, just because I will have a hard time defending such a solution with some colleagues.
As there is no possibility to set a type as the map key, I finally decided to implement the following solution, which is based on #Chrono Kitsune 's solution:
type Postprocess interface {
NeedsPostprocess() bool
}
type MsgWithPostProcess struct {}
func (p *MsgWithPostProcess) NeedsPostprocess() bool {
return true
}
type Msg1 struct {
MsgWithPostProcess
//other stuff
}
type Msg2 struct {
MsgWithPostProcess
//other stuff
}
type Msg3 struct {
//no postprocessing needed
}
func (p *Postprocessor) Process(msgtype interface{}) error {
if _, ok := msgtype.(Postprocess); ok {
//do postprocessing
}
}
As of my simple test I did, only Msg1 and Msg2 will be postprocessed, but not Msg3, which is what I wanted.
This question was the first hit I found on Google but the title is somewhat misleading. So I'll leave this here to add some food for thought with the title of the question in mind.
First, the issue with maps is that its key must be a comparable value. This is why for example a slice cannot be used is a map key. A slice is not comparable and is therefore not allowed. You can use an array (fixed sized slice) but not a slice for the same reason.
Second, you have in the reflect.TypeOf(...).String()a way to get a canonical string representation for types. Though it is not unambiguous unless you include the package path, as you can see here.
package main
import (
"fmt"
s2 "go/scanner"
"reflect"
s1 "text/scanner"
)
type X struct{}
func main() {
fmt.Println(reflect.TypeOf(1).String())
fmt.Println(reflect.TypeOf(X{}).String())
fmt.Println(reflect.TypeOf(&X{}).String())
fmt.Println(reflect.TypeOf(s1.Scanner{}).String())
fmt.Println(reflect.TypeOf(s2.Scanner{}).String())
fmt.Println(reflect.TypeOf(s1.Scanner{}).PkgPath(), reflect.TypeOf(s1.Scanner{}).String())
fmt.Println(reflect.TypeOf(s2.Scanner{}).PkgPath(), reflect.TypeOf(s2.Scanner{}).String())
}
int
main.X
*main.X
scanner.Scanner
scanner.Scanner
text/scanner scanner.Scanner
go/scanner scanner.Scanner
https://play.golang.org/p/NLODZNdik6r
With this information, you can (if you feel so inclined) create a map which let's go from a reflect.Type to a key and back again, like this.
package main
import (
"fmt"
s2 "go/scanner"
"reflect"
s1 "text/scanner"
)
type TypeMap struct {
m []reflect.Type
}
func (m *TypeMap) Get(t reflect.Type) int {
for i, x := range m.m {
if x == t {
return i
}
}
m.m = append(m.m, t)
return len(m.m) - 1
}
func (m *TypeMap) Reverse(t int) reflect.Type {
return m.m[t]
}
type X struct{}
func main() {
var m TypeMap
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(X{})))
fmt.Println(m.Reverse(1))
fmt.Println(m.Get(reflect.TypeOf(&X{})))
fmt.Println(m.Reverse(2))
fmt.Println(m.Get(reflect.TypeOf(s1.Scanner{})))
fmt.Println(m.Reverse(3).PkgPath(), m.Reverse(3))
fmt.Println(m.Get(reflect.TypeOf(s2.Scanner{})))
fmt.Println(m.Reverse(4).PkgPath(), m.Reverse(4))
}
0
int
0
int
0
int
1
main.X
2
*main.X
3
text/scanner scanner.Scanner
4
go/scanner scanner.Scanner
In the above case I'm assuming that N is small. Also note the use of the identity of reflect.TypeOf, it will return the same pointer for the same type on subsequent calls.
If N is not small, you may want to do something a bit more complex.
package main
import (
"fmt"
s2 "go/scanner"
"reflect"
s1 "text/scanner"
)
type PkgPathNum struct {
PkgPath string
Num int
}
type TypeMap struct {
m map[string][]PkgPathNum
r []reflect.Type
}
func (m *TypeMap) Get(t reflect.Type) int {
k := t.String()
xs := m.m[k]
pkgPath := t.PkgPath()
for _, x := range xs {
if x.PkgPath == pkgPath {
return x.Num
}
}
n := len(m.r)
m.r = append(m.r, t)
xs = append(xs, PkgPathNum{pkgPath, n})
if m.m == nil {
m.m = make(map[string][]PkgPathNum)
}
m.m[k] = xs
return n
}
func (m *TypeMap) Reverse(t int) reflect.Type {
return m.r[t]
}
type X struct{}
func main() {
var m TypeMap
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(X{})))
fmt.Println(m.Reverse(1))
fmt.Println(m.Get(reflect.TypeOf(&X{})))
fmt.Println(m.Reverse(2))
fmt.Println(m.Get(reflect.TypeOf(s1.Scanner{})))
fmt.Println(m.Reverse(3).PkgPath(), m.Reverse(3))
fmt.Println(m.Get(reflect.TypeOf(s2.Scanner{})))
fmt.Println(m.Reverse(4).PkgPath(), m.Reverse(4))
}
0
int
1
main.X
2
*main.X
3
text/scanner scanner.Scanner
4
go/scanner scanner.Scanner
https://play.golang.org/p/2fiMZ8qCQtY
Note the subtitles of pointer to type, that, X and *X actually are different types.
Is there a way to use reflect to access unexported fields in Go 1.8?
This no longer seems to work: https://stackoverflow.com/a/17982725/555493
Note that reflect.DeepEqual works just fine (that is, it can access unexported fields) but I can't make heads or tails of that function. Here's a go playarea that shows it in action: https://play.golang.org/p/vyEvay6eVG. The src code is below
import (
"fmt"
"reflect"
)
type Foo struct {
private string
}
func main() {
x := Foo{"hello"}
y := Foo{"goodbye"}
z := Foo{"hello"}
fmt.Println(reflect.DeepEqual(x,y)) //false
fmt.Println(reflect.DeepEqual(x,z)) //true
}
If the struct is addressable, you can use unsafe.Pointer to access the field (read or write) it, like this:
rs := reflect.ValueOf(&MyStruct).Elem()
rf := rs.Field(n)
// rf can't be read or set.
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read and set.
See full example on the playground.
This use of unsafe.Pointer is valid according to the documentation and running go vet returns no errors.
If the struct is not addressable this trick won't work, but you can create an addressable copy like this:
rs = reflect.ValueOf(MyStruct)
rs2 := reflect.New(rs.Type()).Elem()
rs2.Set(rs)
rf = rs2.Field(0)
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read. Setting will succeed but only affects the temporary copy.
See full example on the playground.
Based on cpcallen's work:
import (
"reflect"
"unsafe"
)
func GetUnexportedField(field reflect.Value) interface{} {
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
}
func SetUnexportedField(field reflect.Value, value interface{}) {
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
Elem().
Set(reflect.ValueOf(value))
}
reflect.NewAt might be confusing to read at first. It returns a reflect.Value representing a pointer to a value of the specified field.Type(), using unsafe.Pointer(field.UnsafeAddr()) as that pointer. In this context reflect.NewAt is different than reflect.New, which would return a pointer to a freshly initialized value.
Example:
type Foo struct {
unexportedField string
}
GetUnexportedField(reflect.ValueOf(&Foo{}).Elem().FieldByName("unexportedField"))
https://play.golang.org/p/IgjlQPYdKFR
reflect.DeepEqual() can do it because it has access to unexported features of the reflect package, in this case namely for the valueInterface() function, which takes a safe argument, which denies access to unexported field values via the Value.Interface() method if safe=true. reflect.DeepEqual() will (might) call that passing safe=false.
You can still do it, but you cannot use Value.Interface() for unexported fields. Instead you have to use type-specific methods, such as Value.String() for string, Value.Float() for floats, Value.Int() for ints etc. These will return you a copy of the value (which is enough to inspect it), but will not allow you to modify the field's value (which might be "partly" possible if Value.Interface() would work and the field type would be a pointer type).
If a field happens to be an interface type, you may use Value.Elem() to get to the value contained / wrapped by the interface value.
To demonstrate:
type Foo struct {
s string
i int
j interface{}
}
func main() {
x := Foo{"hello", 2, 3.0}
v := reflect.ValueOf(x)
s := v.FieldByName("s")
fmt.Printf("%T %v\n", s.String(), s.String())
i := v.FieldByName("i")
fmt.Printf("%T %v\n", i.Int(), i.Int())
j := v.FieldByName("j").Elem()
fmt.Printf("%T %v\n", j.Float(), j.Float())
}
Output (try it on the Go Playground):
string hello
int64 2
float64 3
package main
import (
"fmt"
"reflect"
"strings"
"unsafe"
)
type Person1 struct {
W3ID string
Name string
}
type Address1 struct {
city string
country string
}
type User1 struct {
name string
age int
address Address1
manager Person1
developer Person1
tech Person1
}
func showDetails(load, email interface{}) {
if reflect.ValueOf(load).Kind() == reflect.Struct {
typ := reflect.TypeOf(load)
value := reflect.ValueOf(load)
//#1 For struct, not addressable create a copy With Element.
value2 := reflect.New(value.Type()).Elem()
//#2 Value2 is addressable and can be set
value2.Set(value)
for i := 0; i < typ.NumField(); i++ {
if value.Field(i).Kind() == reflect.Struct {
rf := value2.Field(i)
/* #nosec G103 */
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
irf := rf.Interface()
typrf := reflect.TypeOf(irf)
nameP := typrf.String()
if strings.Contains(nameP, "Person") {
//fmt.Println(nameP, "FOUND !!!!!!! ")
for j := 0; j < typrf.NumField(); j++ {
re := rf.Field(j)
nameW := typrf.Field(j).Name
if strings.Contains(nameW, "W3ID") {
valueW := re.Interface()
fetchEmail := valueW.(string)
if fetchEmail == email {
fmt.Println(fetchEmail, " MATCH!!!!")
}
}
}
}
showDetails(irf, email)
} else {
// fmt.Printf("%d.Type:%T || Value:%#v\n",
// (i + 1), value.Field(i), value.Field(i))
}
}
}
}
func main() {
iD := "tsumi#in.org.com"
load := User1{
name: "John Doe",
age: 34,
address: Address1{
city: "New York",
country: "USA",
},
manager: Person1{
W3ID: "jBult#in.org.com",
Name: "Bualt",
},
developer: Person1{
W3ID: "tsumi#in.org.com",
Name: "Sumi",
},
tech: Person1{
W3ID: "lPaul#in.org.com",
Name: "Paul",
},
}
showDetails(load, iD)
}
For some reason, it appears that adding new element to slice using reflection doesn't update slice itself. This is the code to demonstrate:
package main
import (
"fmt"
"reflect"
)
func appendToSlice(arrPtr interface{}) {
valuePtr := reflect.ValueOf(arrPtr)
value := valuePtr.Elem()
value = reflect.Append(value, reflect.ValueOf(55))
fmt.Println(value.Len()) // prints 1
}
func main() {
arr := []int{}
appendToSlice(&arr)
fmt.Println(len(arr)) // prints 0
}
Playground link : https://play.golang.org/p/j3532H_mUL
Is there something I'm missing here?
reflect.Append works like append in that it returns a new slice value.
You are assigning this value to the value variable in the appendToSlice function, which replaces the previous reflect.Value, but does not update the original argument.
To make it more clear what's happening, take the equivalent function to your example without reflection:
func appendToSlice(arrPtr *[]int) {
value := *arrPtr
value = append(value, 55)
fmt.Println(len(value))
}
What you need to use is the Value.Set method to update the original value:
func appendToSlice(arrPtr interface{}) {
valuePtr := reflect.ValueOf(arrPtr)
value := valuePtr.Elem()
value.Set(reflect.Append(value, reflect.ValueOf(55)))
fmt.Println(value.Len())
}
https://play.golang.org/p/Nhabg31Sju
package main
import "fmt"
import "reflect"
type Foo struct {
Name string
}
func main() {
_type := []Foo{}
fmt.Printf("_type: v(%v) T(%T)\n", _type, _type)
reflection := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(_type).Elem()), 0, 0)
reflectionValue := reflect.New(reflection.Type())
reflectionValue.Elem().Set(reflection)
slicePtr := reflect.ValueOf(reflectionValue.Interface())
sliceValuePtr := slicePtr.Elem()
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"a"})))
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"b"})))
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"c"})))
values := []Foo{Foo{"d"}, Foo{"e"}}
for _, val := range values {
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(val)))
}
result := sliceValuePtr.Interface()
fmt.Printf("result: %T = (%v)\n", result, result)
}
take a look at: https://play.golang.org/p/vXOqTVSEleO
I have a struct in which I put all excess data into a map[string]interface{}.
If I unmarshal into the Data property with an empty variable, I don't want to keep it when marshalling. I basically need interface{} to have json:",omitempty", How do I get that?
type Event struct {
From string `json:"from"`
Data map[string]interface{} `json:"data,omitempty"`
}
The omitempty is for encoding values, but not for decoding.
You cannot generate a complete empty map in Go. (Empty as in, it does not exists.) If your create a variable / value of a struct it always has its default value.
package main
import "fmt"
func main() {
var m map[string]interface{}
fmt.Printf("%v %d\n", m, len(m))
// prints: map[] 0
m = nil
fmt.Printf("%v %d\n", m, len(m))
// prints: map[] 0
}
Example: Go Playground.
I'd like to know if there's anything native that supports it. However until then, you can do it via reflection:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func main() {
m := map[string]interface{}{
"should_exist": "foo",
"should_omit": "",
}
for k, v := range m {
if reflect.ValueOf(v).IsZero() {
delete(m, k)
}
}
data, _ := json.Marshal(m)
fmt.Println(string(data)) // {"should_exist":"foo"}
}
Please note the performance hit this might cause in some use cases.