Search code examples
dictionarygogenericsnested

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 don't 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?


Solution

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