Golang抽象Interface Slice转换

标签 go

我有一个对象列表(确切地说是 olievere/Elastic SearchResult.Hits)。其中每个都有一个 json.RawMessage 对象,我希望创建一个可抽象的方法,该方法接受任何结构的接口(interface) slice ,Unmarshal 的每个单独的命中' json.RawMessage 。 > 到所述结构中,并将其附加到传入的 []interface 中。

这个函数不应该对所需的业务层结构有任何逻辑或洞察力,并且数据库调用的接口(interface)相当多,因此对上面提到的 Elastic 包没有可见性。我试图做的示例...

foo.go    
import (bar, package)
type TestStruct struct {    
    Slice []*package.Struct // package.Struct has a value of Source which is a    
                            // json.RawMessage    
}    

func GetData() bar.Test {
    return &TestStruct{*package.GetData()}
}

func (result TestStruct) UnmarshalStruct(v []interface{}) {    
    for _, singleStruct := range result.Slice {     
        append(json.Unmarshal(singleStruct, &v))
    }

第二个文件

bar.go
type Handler interface {
    GetData() Test
}

type Test interface {
    UnmarshalStruct
}

type OtherType struct {
   foo string
   bar string
} 

func RetrieveData() []OtherType {
    handler := New(Handler)
    test := handler.GetData()
    var typeSlice []OtherType    
    test.UnmarshalStruct(&typeSlice)
}

我希望将 []OtherType 类型的内容或我决定创建的任何其他新结构交给 UnmarshalStruct,并让它返回对我来说同样的结构,只是充满了数据

例如,我将从 Elastic 中搜索两种不同类型的数据。我将收到以下两个对象之一的列表。

{ 'foo': '',
  'id': 
}

并且在不同的索引中

{ 'bar': '',
  'baz': '',
  'eee': ''
}     

其中每一个自然都需要两个不同的结构。
但是,我希望有一种方法能够解码这些列表中的任何一个。我将在下面给出,并使用相同的函数,我希望能够将其转换为 bar 结构,并将其他类型转换为 foo 结构。

{ 'source': [
    { 'bar': '',
      'baz': '',
      'eee': ''
    },
    { 'bar': '',
      'baz': '',
      'eee': ''
    },
    { 'bar': '',
      'baz': '',
      'eee': ''
    }    
  ]
}

最佳答案

不经过反射(reflection),真的没有办法做你想做的事。我个人会以不同的方式构建它,以便您解码为更通用的类型,例如 map[string]string,或者如 @ThunderCat 所示,摆脱中间状态并直接解码为正确的类型。但这是可以做到的...

(我将 json.RawMessage 直接移到 TestStruct 中,以消除一级间接性并使示例更加清晰)

type TestStruct struct {
    Slice []json.RawMessage
}

func (t TestStruct) UnmarshalStruct(v interface{}) error {
    // get the a Value for the underlying slice
    slice := reflect.ValueOf(v).Elem()
    // make sure we have adequate capacity
    slice.Set(reflect.MakeSlice(slice.Type(), len(t.Slice), len(t.Slice)))

    for i, val := range t.Slice {
        err := json.Unmarshal(val, slice.Index(i).Addr().Interface())
        if err != nil {
            return err
        }
    }

    return nil
}

然后你就可以这样调用它

var others []OtherType
err := ts.UnmarshalStruct(&others)
if err != nil {
    log.Fatal(err)
}

http://play.golang.org/p/dgly2OOXDG

关于Golang抽象Interface Slice转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29400044/

相关文章:

使用 VGO 和 go.mod 找不到 Go 模块

html - 转到调用 t.Execute 中的许多参数

go - 如何使用gore加载本地go文件

go - 关闭 Go http.Client 的连接池

go - Golang 中的时间布局

c - 尝试扩展 golang Pigpio 包装函数 gpioWaveAddGeneric

google-app-engine - 要传递给 appengine/file.Delete() 的 fileName 的值是?

go - 使用正在运行的 shell 修改 golang Docker 容器

go - 在 sarama-cluster 中模拟 NewConsumer

go - 如何在beego中获取controller之外的cookie和session