头图

在Golang开发中,我们经常会设计各种各样的结构体,然后给各个字段添加各种各样的标签。

例如,使用 json:something 来做 JSON 的序列化和反序列化

package x

type T struct{
  MyField string `json:"my_field"`
}

众所周知,命名是编程中的两大难事之一,当我们有了这些标签之后,我们会面临额外的一些问题如下:

  • 要使用哪种命名风格 驼峰法 camelCase 还是 蛇形法 snake_case ?
  • 如果使用了 camelCase ,对于像 UserID 这样的,应该使用 userId 还是 userID
  • 结构体的字段数量和字段名都是有可能在后续开发中不断变更地,当这些变更发生时,怎么才能快速按照之前的规则来完成这些结构体的被动变更?
  • 如果你的项目有其他人协作,你要怎么来保证所有的开发者或者新人能够快速理解这些既定的约定,并且不需要额外付出人力校对成本去把控这些规范?

虽然我们可以在Lint阶段或者自动化测试里面去检测这些问题,但是我会更偏向于下面的做法:

永远不要通过人工来管理这些标签,而是通过工具化去自动化地生成。

你可以使用 Gozz 来很轻易地实现这个模式:

下面有个很简单的例子,我们想要填充 jsonbson 两种标签给我们的结构体

package tag01

// +zz:tag:json,bson:{{ snake .FieldName }}
type User struct {
    Id        string
    Name      string
    Address   string
    CreatedAt time.Time
    UpdatedAt time.Time
}

只需要在结构体上面加上一个注解 +zz:tag:json,bson:{{ snake .FieldName}}

然后执行 gozz run -p "tag" ./ 

你会发现这些问题就会彻底得到解决,代码的标签会被自动化按模版格式填充:

package tag01

// +zz:tag:json,bson:{{ snake .FieldName }}
type User struct {
    Id        string    `bson:"id" json:"id"`
    Name      string    `bson:"name" json:"name"`
    Address   string    `bson:"address" json:"address"`
    CreatedAt time.Time `bson:"created_at" json:"created_at"`
    UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
}

最后 只需要将这些命令放到项目的 Makefile 在进行构建流水线时自动化执行,或者加到 commit hooks里,这些结构体标签的规范从此以后都不需要人工介入。

上面的例子展示了 gozz-tag 的一些基本功能,下面的例子会额外展示这个工具的一些强大特性:

  • 我们把注解加到了块级的代码定义,结构体的定义,以及字段的定义上
  • 然后对同个 key 使用了不同的模版格式,以及 golang 的模版函数方法
// +zz:tag:json,bson:{{ snake .FieldName }}
type (
    User struct {
        Id        string
        Name      string
        Address   string
        CreatedAt time.Time
        UpdatedAt time.Time
    }

    // +zz:tag:json,bson:{{ camel .FieldName }}
    Book struct {
        Id        string
        Title     string
        CreatedAt time.Time
        UpdatedAt time.Time
    }

    Order struct {
        Id     string
        UserId string
        BookId string
        // +zz:tag:json,bson:{{ upper .FieldName | upper }}
        CreatedAt time.Time
        // +zz:tag:+json:,omitempty
        UpdatedAt time.Time
    }
)

执行 gozz 命令之后 ,文件会被更新为

// +zz:tag:json,bson:{{ snake .FieldName }}
type (
    User struct {
        Id        string    `bson:"id" json:"id"`
        Name      string    `bson:"name" json:"name"`
        Address   string    `bson:"address" json:"address"`
        CreatedAt time.Time `bson:"created_at" json:"created_at"`
        UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
    }

    // +zz:tag:json,bson:{{ camel .FieldName }}
    Book struct {
        Id        string    `bson:"id" json:"id"`
        Title     string    `bson:"title" json:"title"`
        CreatedAt time.Time `bson:"createdAt" json:"createdAt"`
        UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"`
    }

    Order struct {
        Id     string `bson:"id" json:"id"`
        UserId string `bson:"user_id" json:"user_id"`
        BookId string `bson:"book_id" json:"book_id"`
        // +zz:tag:json,bson:{{ snake .FieldName | upper }}
        CreatedAt time.Time `bson:"CREATED_AT" json:"CREATED_AT"`
        // +zz:tag:+json:,omitempty
        UpdatedAt time.Time `bson:"updated_at" json:"updated_at,omitempty"`
    }
)

需求都被完美解决了。

所以,相信在 Gozz 的帮助下,我们已经不需要去人工地维护这些结构体的标签规范了,只需要把注解加在定义块上,然后把生成的命令放到开发流水线中。

实际上,这个功能只是 Gozz 其中一个内置插件,它还提供了很多其他强大的插件,可以帮我们借助注解去做很多更强大的事情,比如 自动化的依赖注入、API路由的自动生成 还有 ORM结构体的生成。

更多详情可以去 github 或者 中文文档 查看,也欢迎给我们点一个 ⭐️。


Maple
2 声望0 粉丝