簡體   English   中英

Golang抽象接口切片轉換

[英]Golang abstracted Interface Slice conversion

我有一個對象列表(精確的是Olivee / Elastic SearchResult.Hits)。 每個對象都有一個json.RawMessage對象,我正在尋找一個可抽象的方法,該方法采用任何結構的接口切片,將json.RawMessage的每個單獨命中的json.RawMessage插入所述結構,並將其附加到傳入的[]interface

不應認為此函數對所需的業務層結構具有任何邏輯或了解,並且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)
}

我正在將[]OtherType類型或我決定創建的任何其他新結構交給UnmarshalStruct ,並讓它返回給我相同的結構,只是裝滿了數據

例如,我要從Elastic搜索兩種不同類型的數據。 我將收到以下兩個對象之一的列表。

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

並在另一個索引中

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

這些中的每一個自然需要兩個不同的結構。
但是,我希望有一種方法能夠解碼這些列表中的任何一個。 我將在下面給出,並使用相同的函數將其轉換為bar結構,將其他類型轉換為foo結構。

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

沒有反射,實際上是沒有辦法做您想要的。 我個人將以不同的方式構造此結構,以便您將其解組為更通用的類型,例如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

如果我理解正確,則需要將數據解組為兩種類型的切片:

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來源

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
}

我知道這不是問題的直接答案,但這是通常如何處理這種情況的方法。

我不認為這很容易做到。 在godocs中的Raw Message Example中,他們在json中使用一個值(在其示例中為“ Space”)來確定要解組的結構類型。

為此,該函數必須具有某種方式來獲取為該程序定義的每個結構,然后它必須檢查每個json對象,並使用反射將其與每個結構進行比較以找出其類型。最有可能的是。 如果存在多個“可能”的結構,該怎么辦? 然后,沖突解決會使事情復雜化。

簡而言之,我認為您無法做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM