首页 文章

Golang抽象出了Interface Slice转换

提问于
浏览
0

我有一个对象列表(olievere / Elastic SearchResult.Hits准确) . 每个对象都有一个 json.RawMessage 对象,并且每个人都会在所述结构中点击' json.RawMessage ,并将其附加到传入的 []interface 中 .

这个func不应该对所需的业务层结构有任何逻辑或洞察力,并且DB Call的接口相当严重,因此无法看到上面提到的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)
}

I'm looking to hand something of type []OtherType, or any other new struct I decide to create, to UnmarshalStruct, and have it return to me that same struct, just full of data

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

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

并在不同的索引

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

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

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

3 回答

  • 1

    没有反思,没有办法做你想做的事 . 我个人会以不同的方式构建它,以便您可以解组为更通用的类型,如 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

  • 0

    如果我理解正确,您希望将数据解组为两种类型的切片:

    type A struct {
      Foo string `json:"foo"`
      ID string `json:"id"`
    }
    
    type B struct {
       Bar string `json:"bar"`
       Baz string `json:"baz"`
       Eee string `json:"eee"`
    }
    

    来自SearchHit Source .

    JSON包可以为您完成大部分工作:

    func executeQuery(q Query, v interface{}) error {
       // Get a SearchHit. I am making this up. 
       // I have no idea how the package works.
       searchHit, err := getHit(q) 
       if err != nil {
          return err
       }
       // This is the important part. Convert the raw message to 
       // a slice of bytes and decode to the caller's slice.
       return json.Unmarshal([]byte(*searchHit.Source), v)
    }
    

    您可以调用此函数来解码一个类型的切片或指向类型的指针切片 .

    // Slice of type
    var s1 []TypeA
    if err := executeQuery(q1, &s1); err != nil {
        // handle error
    }
    
    // Slice of pointer to type
    var s2 []*TypeB
    if err := error(q2, &s2); err != nil {
       // handle error
    }
    

    我知道这不是问题的直接答案,但这是通常处理这种情况的方式 .

  • 1

    我不相信这很容易做到 . 在godocs中的Raw Message Example中,他们使用json中的值,在他们的示例中使用"Space"来确定要解组的结构类型 .

    为了实现这个功能,函数必须有一些方法来获取已经为程序定义的每个结构,然后它必须检查每个json对象并使用反射将它与每个结构进行比较以找出它的类型最有可能的是 . 如果有多个结构“可能是它”怎么办?然后冲突解决使事情复杂化 .

    总之,我不认为你能做到这一点 .

相关问题