Comments 17
UFO just landed and posted this here
Ну про что может быть первый комментарий к статье про Go? Правильно! Про Rust!
+3
UFO just landed and posted this here
Что вы называете «суммированим типов»?
В Go вы просто преобразовываете intrface{} (он по сути объединяет вообще все типы языка) в тип который ожидаете и проверяете ошибку этого преобразования. Если без ошибки — значит все ок — пользуйтесь полученным типом данных. Ну а ошибка — думайте как обработать.
Именно из за обработки ошибок преобразований код такого решения довольно сильно разрастается, но иначе и нельзя.
В Go вы просто преобразовываете intrface{} (он по сути объединяет вообще все типы языка) в тип который ожидаете и проверяете ошибку этого преобразования. Если без ошибки — значит все ок — пользуйтесь полученным типом данных. Ну а ошибка — думайте как обработать.
Именно из за обработки ошибок преобразований код такого решения довольно сильно разрастается, но иначе и нельзя.
0
UFO just landed and posted this here
А можно пример кода, как именно предлагается сделать?
0
UFO just landed and posted this here
Здесь обратная задача, то есть, не в json, а обратно. При этом в условиях задано, что структура неизвестная.
map[string]interface{} — это просто общий интерфейс объекта json. Естественно, что в него декодируется любой объект из json строки.
И да, конечно, переменную типа map[string]interface{} можно создать в коде и потом её кодировать в json, и это было бы решением прямой задачи. Собственно, его код я и спрашивал. Просто интересно, чем конкретно оно лучше. Те решения, что я встречал (через map[string]interface{}), лучшими бы я не назвал.
map[string]interface{} — это просто общий интерфейс объекта json. Естественно, что в него декодируется любой объект из json строки.
И да, конечно, переменную типа map[string]interface{} можно создать в коде и потом её кодировать в json, и это было бы решением прямой задачи. Собственно, его код я и спрашивал. Просто интересно, чем конкретно оно лучше. Те решения, что я встречал (через map[string]interface{}), лучшими бы я не назвал.
0
А что со скоростью?
0
Спасибо, красивое решение… хотя и пришлось вчитаться несколько раз чтобы понять суть задачи и способ ее решения. По сути gob тут простой пересборщик из большой структуры в меньшую. И должен по идее работать быстро.
Но было бы здорово попробовать решить эту задачу «как-то неправильно» и бенчами прогнать в паре с этим решением.
Но было бы здорово попробовать решить эту задачу «как-то неправильно» и бенчами прогнать в паре с этим решением.
0
В чем проблема взять и явно конвертировать исходную обобщённую структуру в нужный набор урезанных и не мудрить с аттрибутами?
В том месте, где вы принимаете решение какое представление внедрить почему просто не вернуть признак желаемого представления и не сделать фабричный метод который вернет нужный вам JSON? Сериализовать в gob, чтобы десериализовать из gob, чтобы сериализовать в JSON… Как-то такие решения должны настораживать их авторов
В том месте, где вы принимаете решение какое представление внедрить почему просто не вернуть признак желаемого представления и не сделать фабричный метод который вернет нужный вам JSON? Сериализовать в gob, чтобы десериализовать из gob, чтобы сериализовать в JSON… Как-то такие решения должны настораживать их авторов
0
Если я правильно понял, то Вы предлагаете использовать дополнительный приватный атрибут типа
И именно в него положить всю логику преобразования в json.
При этом для каждого отображения нужно иметь свою функцию. Теперь вопрос: а что будет в тех функциях? типа такого:
Если как по мне, то читабельности и разделения кода становится на порядок меньше, хотя как показывают замеры скорости, это будет быстрее.
Или имелось в виду совсем другое решение?
toJson func() (data []byte, err error)
И именно в него положить всю логику преобразования в json.
При этом для каждого отображения нужно иметь свою функцию. Теперь вопрос: а что будет в тех функциях? типа такого:
return json.Marshal(&struct {
Id int64 `json:"ref"`
Title string `json:"title"`
Description string `json:"description"`
PromoPrice int64 `json:"price"`
PromoDescription string `json:"promo,omitempty"`
Links Links `json:"links"`
}{
Id: b.Id,
Title: b.Title,
Description: b.Description,
PromoPrice: b.PromoPrice,
PromoDescription: b.PromoDescription,
Links: b.Links,
})
Если как по мне, то читабельности и разделения кода становится на порядок меньше, хотя как показывают замеры скорости, это будет быстрее.
Или имелось в виду совсем другое решение?
0
Про скорость и бенчмарки. (в ответ TonyLorencio, Sly_tom_cat и, кончено, всем, кому интересно).
Главный вопрос тут, конечно, про целесообразность использования gob, и дополнительного кодирования/декодирования, поэтому давайте рассмотрим именно этот момент.
Вообще, решение конечно более архитектурное, направленное на разделение кода, чтобы при сливании git веток меньше приходилось править конфликты, которые бы были неизбежны, если бы всё решение было внутри функции MarshalJSON.
Итак, давайте сделаем тоже самое, но без использования gob, а с прямым заполнением структуры. В коде есть закомментированный текст — о нём будет далее.
Тест создаёт список из элементов и потом получает json строку. Результаты:
То есть, использование gob даёт замедление в 10 раз. Да, это несколько больше, чем ожидалось.
Но это простые типы данных: int64 и string. А что будет, если будет что-то посложнее? Давайте добавим список литературы.
Пусть всегда будет по списку литературу в 100 позиций. Результаты уже не столь плачевны:
BenchmarkRun0-8 3000 493611 ns/op
BenchmarkRun1-8 5000 322898 ns/op
Замедление уже составляет 52%. При более сложных данных может быть и меньше.
Если вам нужно выводить до 100 элементов, при этом их структура достаточно сложная, то замедление будет не столь критичным. Если это тонны информации, и каждая миллисекунда на счету, то, возможно, то данное решение может быть не очень эффективным.
Да, это плата за разделение кода, уменьшение риска конфликтов при слиянии git веток, наглядность моделей. Возможно, этого всего можно добиться и без gob, или с ним, но другим, более эффективным решением. Если найду — обязательно поделюсь.
Главный вопрос тут, конечно, про целесообразность использования gob, и дополнительного кодирования/декодирования, поэтому давайте рассмотрим именно этот момент.
Вообще, решение конечно более архитектурное, направленное на разделение кода, чтобы при сливании git веток меньше приходилось править конфликты, которые бы были неизбежны, если бы всё решение было внутри функции MarshalJSON.
Итак, давайте сделаем тоже самое, но без использования gob, а с прямым заполнением структуры. В коде есть закомментированный текст — о нём будет далее.
book1.go
package models
import (
"encoding/json"
"fmt"
"time"
)
const (
SiteBook1View = iota
Partner1Book1View
Partner2Book1View
PromoBook1View
)
func (b *Book1) SetDefaultView() {
b.SetSiteView()
}
func (b *Book1) SetSiteView() {
b.view = SiteBook1View
}
func (b *Book1) SetPartner1View() {
b.view = Partner1Book1View
}
func (b *Book1) SetPartner2View() {
b.view = Partner2Book1View
}
func (b *Book1) SetPromoView() {
b.view = PromoBook1View
}
type Book1 struct {
Id int64
Title string
Description string
Partner2Title string
Price int64
PromoPrice int64
PromoDescription string
Partner1Price int64
Partner2Price int64
// Links Links
UpdatedAt time.Time
CreatedAt time.Time
view int
}
func (b Book1) MarshalJSON() (data []byte, err error) {
if b.view == 0 {
b.SetDefaultView()
}
switch b.view {
case SiteBook1View:
return json.Marshal(SiteBookView{
Id: b.Id,
Title: b.Title,
Description: b.Description,
Price: b.Price,
// Links: b.Links,
})
case Partner1Book1View:
return json.Marshal(Partner1BookView{
Id: b.Id,
Title: b.Title,
Partner1Price: b.Partner1Price,
// Links: b.Links,
})
case Partner2Book1View:
return json.Marshal(Partner2BookView{
Id: b.Id,
Partner2Title: b.Partner2Title,
Description: b.Description,
Partner2Price: b.Partner2Price,
// Links: b.Links,
})
case PromoBook1View:
return json.Marshal(PromoBookView{
Id: b.Id,
Title: b.Title,
Description: b.Description,
PromoPrice: b.PromoPrice,
PromoDescription: b.PromoDescription,
// Links: b.Links,
})
default:
err = fmt.Errorf("undefined view")
return
}
return
}
Тест создаёт список из элементов и потом получает json строку. Результаты:
BenchmarkRun0-8 20000 68701 ns/op
BenchmarkRun1-8 200000 7177 ns/op
То есть, использование gob даёт замедление в 10 раз. Да, это несколько больше, чем ожидалось.
Но это простые типы данных: int64 и string. А что будет, если будет что-то посложнее? Давайте добавим список литературы.
Код LInks
type Link struct {
Title string
Description string
Rate float64
}
type Links []Link
type Book struct {
Id int64
Title string
Description string
Partner2Title string
Price int64
PromoPrice int64
PromoDescription string
Partner1Price int64
Partner2Price int64
Links Links
UpdatedAt time.Time
CreatedAt time.Time
view BookView
}
type SiteBookView struct {
Id int64 `json:"sku"`
Title string `json:"title"`
Description string `json:"description"`
Price int64 `json:"price"`
Links Links `json:"links"`
}
//к остальным также добавим Links с каким-то json всевдонимом
Пусть всегда будет по списку литературу в 100 позиций. Результаты уже не столь плачевны:
BenchmarkRun0-8 3000 493611 ns/op
BenchmarkRun1-8 5000 322898 ns/op
Замедление уже составляет 52%. При более сложных данных может быть и меньше.
Если вам нужно выводить до 100 элементов, при этом их структура достаточно сложная, то замедление будет не столь критичным. Если это тонны информации, и каждая миллисекунда на счету, то, возможно, то данное решение может быть не очень эффективным.
Да, это плата за разделение кода, уменьшение риска конфликтов при слиянии git веток, наглядность моделей. Возможно, этого всего можно добиться и без gob, или с ним, но другим, более эффективным решением. Если найду — обязательно поделюсь.
0
Sign up to leave a comment.
Articles
Change theme settings
Динамическое изменение схемы JSON в Go с помощью gob