TGViewer
Библиотека Go-разработчика | Golang Библиотека Go-разработчика | Golang @goproglib · 24.1K subscribers
Post #7337 2.86K
📎 Сравнение двух Go-структур без хардкода полей. Часть 2, идея с тегами

В первой части мы упёрлись в стену из почти одинаковых блоков if, которая растёт с каждым новым полем. Теперь зададим другой вопрос. Что если логика сравнения вообще не будет упоминать ни одного имени поля?

У полей Go-структуры можно хранить метаданные через теги, те самые строки в обратных кавычках. GORM по тегу gorm:"column:name" знает, в какую колонку базы ложится поле. JSON по тегу json:"name" знает имя в JSON. Это просто строки, которые рантайм умеет читать обратно через рефлексию.

Обе стороны сравнения уже размечены. Модель базы знает свои колонки. Нужно лишь, чтобы входящий DTO объявил, какой колонке соответствует каждое его поле. Поэтому добавляем ещё один тег:
type DriverDriver struct {
Name string `json:"name" match:"name"`
Number string `json:"number" match:"number"`
ProfilePic *string `json:"profile_pic" match:"profile_pic"`
}


Тег match:"name" это весь контракт. Он говорит, что это поле надо сравнивать с колонкой базы по имени name. Правило маппера получается таким. Для каждого поля DTO с тегом match найди поле базы, у которого колонка gorm равна этому тегу, сравни их, и если различаются, запиши новое значение под именем колонки.

Ни одно имя поля не зашито в логику. Определения структур сами становятся конфигурацией. Добавили поле и тег, оно автоматически попало в сравнение. Удалили, оно выпало. Сам маппер при этом не меняется. Вызов выглядит как одна строка на модель:
driverUpdates, err := mapper.CompareAndMap(driver.DriverDriver, dbUser)
metaUpdates, err := mapper.CompareAndMap(driver.DriverMeta, dbUser)
vehicleUpdates, _ := mapper.CompareAndMap(driver.Vehicle, dbVehicle)


Каждый вызов возвращает map[string]any только из изменившихся колонок, и это ровно та форма, которую ждёт Updates() у GORM. Обратите внимание, второй и третий вызовы сравнивают совсем разные типы структур с разными таблицами одной и той же функцией.

В следующей части разберём, как этот маппер устроен внутри.

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoDeep
  • 🌚 1
More from @goproglib
  1. Sep 25, 2026🤡🤡 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
  2. Sep 25, 2026💡 Код работает. А data race уже есть В Go можно записать значение в одной горутине, прочи…
  3. Sep 23, 2026💥 TCP/IP: что происходит с данными в сети Когда Go-приложение отправляет данные по сети,…
  4. Sep 22, 2026🔴 Встроенные функции len, make, panic — встроенные функции Go, которые можно использовать…
  5. Sep 21, 2026🤩 Go с нуля: серия базовых шпаргалок Собрали путь от Hello, World! до goroutines, channel…
  6. Sep 20, 2026🤔 Вопрос с собеседования по Go Что выведет программа? ❤️ — [1 2 3 4 5] / [1 2 10] 🔥 — [1…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →