Я реализовал очень простой метод Decode (используя пока gob.Decoder
) — он хорошо работает для одиночных ответов — он будет хорошо работать даже для фрагментов, но мне нужно реализовать метод DecodeMany, где он может декодировать набор отдельных ответов ( не кусок).
Метод рабочего декодирования:
var v MyType
_ = Decode(&v)
...
func Decode(v interface{}) error {
buf, _ := DoSomething() // func DoSomething() ([]byte, error)
// error handling omitted for brevity
return gob.NewDecoder(bytes.NewReader(buf)).Decode(v)
}
Что я пытаюсь сделать для метода DecodeMany, так это иметь дело с ответом, который не обязательно является фрагментом:
var vv []MyType
_ = DecodeMany(&vv)
...
func DecodeMany(vv []interface{}) error {
for _, g := range DoSomething() { // func DoSomething() []struct{Buf []bytes}
// Use g.Buf as an individual "interface{}"
// want something like:
var v interface{} /* Somehow create instance of single vv type? */
_ = gob.NewDecoder(bytes.NewReader(g.Buf)).Decode(v)
vv = append(vv, v)
}
return
}
Помимо того, что не компилируется вышеизложенное, также возникает ошибка:
cannot use &vv (value of type *[]MyType) as type []interface{} in argument to DecodeMany
Если вы хотите изменить переданный фрагмент, это должен быть указатель, иначе вы должны вернуть новый фрагмент. Кроме того, если функция объявлена как имеющая параметр типа []interface{}
, вы можете передать только значение типа []interface{}
и никакие другие типы фрагментов... Если только вы не используете дженерики...
Это прекрасный пример для начала использования дженериков, представленных в Go 1.18.
Измените DecodeMany()
на общий, чтобы параметр типа T
был типом элемента среза:
func DecodeMany[T any](vv *[]T) error {
for _, g := range DoSomething() {
var v T
if err := gob.NewDecoder(bytes.NewReader(g.Buf)).Decode(&v); err != nil {
return err
}
*vv = append(*vv, v)
}
return nil
}
Вот простое приложение для проверки:
type MyType struct {
S int64
}
func main() {
var vv []MyType
if err := DecodeMany(&vv); err != nil {
panic(err)
}
fmt.Println(vv)
}
func DoSomething() (result []struct{ Buf []byte }) {
for i := 3; i < 6; i++ {
buf := &bytes.Buffer{}
v := MyType{S: int64(i)}
if err := gob.NewEncoder(buf).Encode(v); err != nil {
panic(err)
}
result = append(result, struct{ Buf []byte }{buf.Bytes()})
}
return
}
Это выводит (попробуйте на Игровая площадка):
[{3} {4} {5}]
Если вы решите вернуть срез, вам не нужно ничего передавать, но вам нужно присвоить результат:
func DecodeMany[T any]() ([]T, error) {
var result []T
for _, g := range DoSomething() {
var v T
if err := gob.NewDecoder(bytes.NewReader(g.Buf)).Decode(&v); err != nil {
return result, err
}
result = append(result, v)
}
return result, nil
}
Используй это:
vv, err := DecodeMany[MyType]()
if err != nil {
panic(err)
}
fmt.Println(vv)
Попробуйте это на Игровая площадка.