'Generics with nested maps

Currently I am using some code like this:

package hello

type object map[string]interface{}

func (o object) get(key string) object {
   val, _ := o[key].(object)
   return val
}

func (o object) getInt(key string) int {
   val, _ := o[key].(int)
   return val
}

but the issue is, I have to write a function for every type I want to return. I tried using something like this:

package hello

type object map[string]interface{}

// syntax error: method must have no type parameters
func (o object) get[T object|int](key string) T {
   val, _ := o[key].(T)
   return val
}

then I did this:

package hello

type object map[string]interface{}

type token[T object|int] struct {
   in object
   out T
}

func (t token[T]) get(key string) token[T] {
   t.out, _ = t.in[key].(T)
   return t
}

which compiles, but since in never gets updated, I dont think I could do chaining, for a nested map:

something.get("one").get("two").get("three")

Is it possible to do something with generics, to give a similar result to my original code, but without having the copy paste functions?

go


Solution 1:[1]

I think I figured it out. You can create a wrapper type, that holds the current object, as well as the output value. If anyone has other ideas, I am interested in them as well:

package main

type object map[string]interface{}

type token[T any] struct {
   object
   value T
}

func newToken[T any](m object) token[T] {
   return token[T]{object: m}
}

func (t token[T]) get(key string) token[T] {
   switch val := t.object[key].(type) {
   case object:
      t.object = val
   case T:
      t.value = val
   }
   return t
}

Example:

package main

func main() {
   obj := object{
      "one": object{
         "two": object{"three": 3},
      },
   }
   three := newToken[int](obj).get("one").get("two").get("three")
   println(three.value == 3)
}

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 three