泛型与嵌套映射

huangapple go评论83阅读模式
英文:

Generics with nested maps

问题

目前我正在使用类似这样的代码:

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
}

但问题是,我必须为每种要返回的类型编写一个函数。我尝试使用类似这样的代码:

package hello

type object map[string]interface{}

// 语法错误:方法不能有类型参数
func (o object) get[T object|int](key string) T {
   val, _ := o[key].(T)
   return val
}

然后我尝试了这样的代码:

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
}

这段代码可以编译通过,但由于in从未更新,我认为我无法进行链式调用,例如对于嵌套的映射:

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

是否有可能使用泛型来实现与我的原始代码类似的结果,但不需要复制粘贴函数?

英文:

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?

答案1

得分: 1

我想我弄明白了。你可以创建一个包装类型,它包含当前对象以及输出值。如果有其他想法,我也很感兴趣:

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
}

示例:

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)
}
英文:

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

huangapple
  • 本文由 发表于 2022年3月18日 00:50:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/71516163.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定