Golang中如何管理数百个结构体?
Golang中如何管理数百个结构体? 所有示例最多只使用了3个结构体。我找不到任何展示如何管理数百个结构体的示例或教程。
type Person struct {
FirstName, LastName string
Age int
}
我已经设法在数据库中存储和获取许多SQL查询,但这似乎不适用于结构体。是这样吗?
提前感谢。
嗨,Silbert,你能详细说明一下你提到的管理结构体是什么意思吗?你是在问如何从数据库中存储/检索它们,还是如何为所有这些结构体组织源代码,等等?
更多关于Golang中如何管理数百个结构体?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
那么,对于你原帖中的例子:
Sibert:
type Person struct { FirstName, LastName string Age int }
你能展示一下你是如何使用它的吗?
你的问题域中有多少结构体类型?100个似乎有点多。
有100张表对应不同的结构体。考虑到使用连接(JOIN)的查询,我估计至少是这个数量的两倍。
我知道可以使用更多的包,但有哪些选择呢?
正如我们之前所说,对于查询操作,完全不需要使用结构体。如果你真的不想使用结构体,你仍然可以使用 map[string]interface{},但你确实不应该这样做,使用它远比创建所需的结构体来完成正确操作要糟糕得多。
NobbZ:
这并不是一个硬性要求,尽管它能让事情变得更简单……
NobbZ:
只需将你的数据组织到包中,或者当查询仅需返回一个简单的单一值时,完全可以省略结构体……
那么有哪些选项呢?除了创建更多的包?
Sibert:
如果有数百个SQL语句对应不同的结构体,将100多个结构体放在一个main.go文件中似乎有些令人难以承受。
你的问题域中有多少种结构体类型?100个似乎有点过多。无论如何,如果结构体的数量增加,你总是可以将其拆分到一个单独的文件中,并将与该结构体相关的每个函数都放在该文件中。首先,随着main.go文件的增长,将你的结构体组织到不同的文件中;然后,随着文件数量的增长,再将你的结构体组织到不同的包中。
[quote=“ditchx, post:11, topic:17473”] 您或许可以为他们自动生成结构体。可以使用类似 db2struct 这样的工具,或者自己动手编写一个。 [/quote]
感谢您的建议。您可以将我的问题归纳为四点:
- 创建结构体(类似 db2struct?)
- 存储结构体(用包?)
make([]Struct)(100 个结构体 = 100 次查询?)- 扫描结构体(100 次查询?)
我认为 sqlx 可以解决第 4 点,但我还没有评估过它……
skillian: 你能澄清一下你所说的管理结构体是什么意思吗?你是想问如何在数据库中存储/检索它们,还是如何为所有这些结构体保持源代码的组织性,
从 SQL 数据库获取数据时,你需要有一个结构体。对吧?如果有成百上千个使用不同结构体的 SQL 查询,把 100 多个结构体都放在一个 main.go 文件里似乎让人难以招架。我曾想过将结构体与查询语句存放在一起,但这似乎是一条单行道,因为结构体必须定义在全局层面。
因此,我正在寻找一种管理数百个结构体的方法,以便能够轻松地维护它们。
如果能够将结构体与查询语句存放在一起,维护起来应该会更容易。我想……
有什么想法吗?
Sibert:
从 SQL 数据库获取数据时,你需要有一个结构体
这并不是必须的,尽管它会让事情变得更容易……
Sibert:
如果有成百上千个使用不同结构体的 SQL 语句,把 100 多个结构体都放在一个 main.go 文件里似乎让人难以招架
一般来说,在 main.go 文件中拥有超过大约 100 行代码似乎就让人难以招架了……通常我只是准备环境,然后调用其他包,或者启动执行真正繁重任务的 goroutine。
Sibert:
有什么想法吗?
只需将你的数据组织到不同的包中,或者当查询只需要返回一个简单的单一值时,完全可以省略结构体……
skillian:
你能展示一下你是怎么使用的吗?
这是我的简单结构体:
type Rec struct {
Id int
Subject string
}
以及使用该结构体的代码:
func Get(query string) interface{} {
rows, err := db.Query(query)
if err != nil {
fmt.Println(err)
}
defer rows.Close()
list := make([]Rec, 0)
for rows.Next() {
rec := Rec{}
err := rows.Scan(&rec.Id, &rec.Subject)
if err != nil {
fmt.Println(err)
}
list = append(list, rec)
}
err = rows.Err()
if err != nil {
fmt.Println(err)
}
return list
}
您或许可以自动为它们生成结构体。可以使用像 db2struct 这样的工具,或者自己编写一个。
与其为连接查询创建一个单独的结构体,您可以选择在结构体中包含一个成员,该成员指向代表连接表的结构体。
假设您有一个用于 users 表的 User 结构体,一个用于 profiles 表的 Profile 结构体。
type User struct {
Username string
Profile *Profile
}
type Profile struct {
About string
Owner *User
}
因此,连接这两个表并将结果读入结构体看起来会像这样:
q := "SELECT users.username, profiles.about FROM users INNER JOIN profiles ON users.user_id=profiles.user_id"
rows, err := db.Query(q)
if err != nil {
fmt.Println(err)
}
defer rows.Close()
list := make([]User, 0)
for rows.Next() {
u := User{Profile: &Profile{}}
err := rows.Scan(&u.Username, &u.Profile.About)
if err != nil {
fmt.Println(err)
}
list = append(list, u)
}
err = rows.Err()
if err != nil {
fmt.Println(err)
}
return list
在Go中管理数百个结构体时,通常需要结合设计模式和代码组织策略。以下是几种实用的方法:
1. 使用包和模块化组织
// models/person.go
package models
type Person struct {
FirstName, LastName string
Age int
}
// models/employee.go
package models
type Employee struct {
Person
EmployeeID string
Department string
}
// models/customer.go
package models
type Customer struct {
Person
CustomerID string
Tier string
}
2. 工厂模式创建实例
// factory/struct_factory.go
package factory
import "your-project/models"
func CreatePerson(firstName, lastName string, age int) models.Person {
return models.Person{
FirstName: firstName,
LastName: lastName,
Age: age,
}
}
func CreateEmployee(person models.Person, empID, dept string) models.Employee {
return models.Employee{
Person: person,
EmployeeID: empID,
Department: dept,
}
}
3. 使用接口统一管理
// interfaces/entity.go
package interfaces
type Entity interface {
GetID() string
Validate() error
ToMap() map[string]interface{}
}
// models/person.go 实现接口
func (p Person) GetID() string {
return fmt.Sprintf("%s-%s", p.FirstName, p.LastName)
}
func (p Person) Validate() error {
if p.Age < 0 {
return errors.New("age cannot be negative")
}
return nil
}
4. 注册表模式管理结构体
// registry/struct_registry.go
package registry
import "reflect"
var structRegistry = make(map[string]reflect.Type)
func RegisterStruct(name string, typ reflect.Type) {
structRegistry[name] = typ
}
func CreateInstance(name string) interface{} {
if typ, exists := structRegistry[name]; exists {
return reflect.New(typ).Interface()
}
return nil
}
// 初始化时注册
func init() {
RegisterStruct("Person", reflect.TypeOf(models.Person{}))
RegisterStruct("Employee", reflect.TypeOf(models.Employee{}))
}
5. 使用代码生成工具
// 使用go:generate自动生成代码
//go:generate go run github.com/vektra/mockery/v2 --name=Entity --output=mocks
// 或使用结构体标签自动生成验证、序列化代码
type Person struct {
FirstName string `json:"first_name" validate:"required"`
LastName string `json:"last_name" validate:"required"`
Age int `json:"age" validate:"min=0,max=150"`
}
6. 数据库映射示例
// repository/person_repo.go
package repository
import (
"database/sql"
"your-project/models"
)
type PersonRepository struct {
db *sql.DB
}
func (r *PersonRepository) GetAll() ([]models.Person, error) {
rows, err := r.db.Query("SELECT first_name, last_name, age FROM persons")
if err != nil {
return nil, err
}
defer rows.Close()
var persons []models.Person
for rows.Next() {
var p models.Person
if err := rows.Scan(&p.FirstName, &p.LastName, &p.Age); err != nil {
return nil, err
}
persons = append(persons, p)
}
return persons, nil
}
// 批量操作
func (r *PersonRepository) BatchCreate(persons []models.Person) error {
tx, err := r.db.Begin()
if err != nil {
return err
}
stmt, err := tx.Prepare("INSERT INTO persons (first_name, last_name, age) VALUES (?, ?, ?)")
if err != nil {
return err
}
defer stmt.Close()
for _, p := range persons {
_, err := stmt.Exec(p.FirstName, p.LastName, p.Age)
if err != nil {
tx.Rollback()
return err
}
}
return tx.Commit()
}
7. 使用依赖注入容器
// container/container.go
package container
import "sync"
type Container struct {
services map[string]interface{}
mu sync.RWMutex
}
func (c *Container) Register(name string, service interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
c.services[name] = service
}
func (c *Container) Get(name string) interface{} {
c.mu.RLock()
defer c.mu.RUnlock()
return c.services[name]
}
// 使用
var container = &Container{
services: make(map[string]interface{}),
}
func init() {
container.Register("PersonService", &services.PersonService{})
container.Register("EmployeeService", &services.EmployeeService{})
}
管理数百个结构体的关键在于良好的代码组织和架构设计。通过合理的包划分、接口抽象和设计模式应用,可以有效管理大量结构体。数据库操作与结构体管理并不冲突,可以使用Repository模式将两者结合。

