2015-04-01 3 views
0

У меня есть список объектов (olievere/Elastic SearchResult.Hits, если быть точным). Каждый из них имеет объект json.RawMessage, и я ищу для создания абстрактного метода, который принимает срединный срез любой структуры, каждый отдельный клик Unmarshal 'json.RawMessage в указанную структуру и добавляет его к переданному в []interface.Golang abstracted Interface Slice conversion

Этот функционал не должен иметь никакой логики или понимания желаемой структуры бизнес-уровня, а вызов БД сопряжен довольно тяжело и, как таковой, не имеет видимости в упомянутом выше пакете 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': '' 
    }  
    ] 
} 
+1

Я не вижу вопрос. У вас проблема с: https://golang.org/doc/faq#convert_slice_of_interface? – JimB

+0

Да, просьба дать более подробную информацию о проблеме, которую вы испытываете. – robbrit

+0

Обновлено жирным шрифтом. Я ищу, чтобы передать что-то типа [] OtherType или любую другую новую структуру, которую я решил создать, для UnmarshalStruct, и вернуть мне эту ту же структуру, просто заполненную данными – user2402831

ответ

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

Это прекрасно, и именно то, что я искал. Я хотел, чтобы это было настолько абстрактным, насколько это возможно для моих конкретных ограничений архитектуры, возможно, у меня есть это построенное странно в другом смысле, но это место. Большое спасибо. – user2402831

1

Если я правильно понимаю, вы хотите, чтобы распаковать данные в срезах двух типов:

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 
} 

Я знаю, что это не прямой ответ на вопрос, но так обычно рассматривается этот сценарий.

0

Я не считаю, что это легко сделать. В Raw Message Example в godocs они используют значение в json, «Space» в своем примере, чтобы определить, какой тип структуры следует отменить.

Для того, чтобы это сработало, функция должна была иметь некоторый способ получения каждой структуры, которая была определена когда-либо для программы, а затем она должна будет исследовать каждый объект json и сравнить его с каждой структурой, используя отражение для фигуры из какого типа это наиболее вероятно. И что, если есть несколько структур, которые «могли бы быть»? Тогда разрешение конфликтов усложняет ситуацию.

Короче говоря, я не думаю, что вы можете это сделать.

Смежные вопросы