golang基于Go类型生成任意代码及类型转换器插件库copygen的使用

Golang基于Go类型生成任意代码及类型转换器插件库Copygen的使用

Copygen Logo

Copygen是一个命令行和程序化的代码生成器,可以生成基于类型的自定义代码,包括类型到类型和字段到字段的代码,而无需向项目添加任何反射或依赖项。

什么是Copygen?

Copygen是一个基于类型的代码生成器,可以避免编写重复代码而浪费时间。它支持所有Go类型,包括basicarrayslicemapchaninterfacefunc类型。

如何使用Copygen?

步骤1. 定义Go类型

在文件中定义Go类型。

./domain/domain.go

// Package domain包含业务逻辑模型。
package domain

// Account表示用户账户。
type Account struct {
	ID     int
	UserID string
	Name   string
	Other  string // 其他字段未使用。
}

./models/model.go

// Package models包含数据存储模型(如数据库)。
package models

// Account表示账户的数据模型。
type Account struct {
	ID       int
	Name     string
	Password string
	Email    string
}

// User表示用户的数据模型。
type User struct {
	UserID   int
	Name     string
	UserData string
}

步骤2. 配置设置文件

使用YMLGO文件设置Copygen。

setup.yml

# 定义代码生成的位置。
generated:
  setup: ./setup.go
  output: ../copygen.go

  # 定义用于生成文件的可选自定义模板(支持.go、.tmpl)。
  # template: ./generate.go

# 定义自定义选项(传递给生成器选项)以进行自定义。
custom:
  option: 可能性是无限的。

setup.go

/* 指定生成文件的包名。 */
package copygen

/* Copygen定义了生成的函数。 */
type Copygen interface {
  // custom 查看下表获取选项
  ModelsToDomain(*models.Account, *models.User) *domain.Account
}

步骤3. 使用命令行

安装命令行工具Copygen:

go install github.com/switchupcb/copygen@latest

运行可执行文件:

copygen -yml path/to/yml

输出示例

生成的copygen.go文件:

// Code generated by github.com/switchupcb/copygen
// DO NOT EDIT.

// Package copygen包含copygen生成代码的设置信息。
package copygen

import (
	c "strconv"

	"github.com/switchupcb/copygen/examples/main/domain"
	"github.com/switchupcb/copygen/examples/main/models"
)

// Itoa将整数转换为ASCII值。
func Itoa(i int) string {
	return c.Itoa(i)
}

// ModelsToDomain将*models.Account、*models.User复制到*domain.Account。
func ModelsToDomain(tA *domain.Account, fA *models.Account, fU *models.User) {
	// *domain.Account字段
	tA.ID = fA.ID
	tA.UserID = Itoa(fU.UserID)
	tA.Name = fA.Name
}

自定义选项

Copygen提供了多种选项来自定义代码生成:

选项 用途 描述 示例
automatch field 选择性使用自动匹配器 使用maptag会禁用默认自动匹配器 automatch package.Type.Field
map from to 手动映射字段 将字段相互映射 map models.Account.ID domain.Account.ID
tag field key 使用结构标签映射字段 使用标签键 tag package.Type.Field key
depth field level 使用特定字段深度 覆盖默认深度 depth models.Account.* 1
deepcopy field 深度复制字段 默认浅拷贝 deepcopy package.Type.Field
custom option 指定自定义函数选项 与模板一起使用 ignore true

转换和类型转换

使用convert function field选项控制类型或字段在匹配时的复制方式:

/* 使用正则表达式定义此转换器应用的函数和字段。 */
// convert .* models.User.UserID
// Itoa将整数转换为ASCII值。
func Itoa(i int) string {
	return c.Itoa(i)
}

使用场景

Copygen的默认目的是通过生成代码来映射对象,从而节省时间。典型使用场景包括:

  • 在不同的模型类型(如domaindatabase)之间转换
  • 生成业务逻辑仓库包
  • 为API请求生成包装函数

许可证

Copygen使用AGPLv3许可证。生成的代码可以不受限制地使用(包括专有和商业用途),但对Copygen软件源代码的修改或以编程方式在大型工作中实现Copygen需要遵守AGPLv3许可证。

完整示例Demo

以下是一个完整的示例,展示如何使用Copygen生成类型转换代码:

  1. 首先定义你的领域模型和数据模型(如上所示)
  2. 创建setup.yml和setup.go配置文件
  3. 运行Copygen生成代码
  4. 使用生成的函数进行类型转换
// 使用生成的函数
func main() {
    // 创建模型实例
    modelAcc := &models.Account{ID: 1, Name: "John"}
    modelUser := &models.User{UserID: 123, Name: "Doe"}
    
    // 转换为领域模型
    domainAcc := ModelsToDomain(modelAcc, modelUser)
    
    fmt.Printf("转换结果: %+v\n", domainAcc)
}

这个示例展示了如何轻松地在不同模型之间转换数据,而无需手动编写重复的赋值代码。


更多关于golang基于Go类型生成任意代码及类型转换器插件库copygen的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于Go类型生成任意代码及类型转换器插件库copygen的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用CopyGen生成Go代码和类型转换器

CopyGen是一个强大的Go代码生成工具,它可以基于现有类型自动生成代码,特别适合处理类型转换、DTO映射等重复性工作。

CopyGen基本使用

安装

go install github.com/switchupcb/copygen@latest

基本概念

CopyGen通过编写YAML配置文件来定义代码生成规则,然后基于这些规则生成Go代码。

示例:类型转换

假设我们有以下两个结构体:

// 用户数据库模型
type UserDB struct {
    ID        int
    Username  string
    Email     string
    CreatedAt time.Time
}

// 用户API响应模型
type UserAPI struct {
    ID       string `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
}

1. 创建copygen.yml配置文件

# copygen.yml
generators:
  user_converter:
    output: ./gen/user_converter.go
    package: gen
    imports:
      - "time"
    functions:
      - name: ConvertDBToAPI
        from: UserDB
        to: UserAPI
        fields:
          - from: ID
            to: ID
            transform: "strconv.Itoa(from)"
          - from: Username
            to: Username
          - from: Email
            to: Email

2. 运行CopyGen

copygen

3. 生成的代码

CopyGen会生成类似以下的代码:

// Code generated by copygen. DO NOT EDIT.

package gen

import (
	"strconv"
	"time"
)

// ConvertDBToAPI converts UserDB to UserAPI.
func ConvertDBToAPI(from UserDB) UserAPI {
	return UserAPI{
		ID:       strconv.Itoa(from.ID),
		Username: from.Username,
		Email:    from.Email,
	}
}

高级用法

自定义转换函数

functions:
  - name: ConvertDBToAPI
    from: UserDB
    to: UserAPI
    fields:
      - from: ID
        to: ID
        custom: "formatUserID(from.ID)"

然后在自定义模板中添加:

func formatUserID(id int) string {
    return fmt.Sprintf("user_%d", id)
}

嵌套结构转换

对于嵌套结构,可以这样配置:

functions:
  - name: ConvertOrderDBToAPI
    from: OrderDB
    to: OrderAPI
    fields:
      - from: User
        to: User
        function: ConvertDBToAPI

多个转换方向

functions:
  - name: ConvertDBToAPI
    from: UserDB
    to: UserAPI
    fields: [...]
    
  - name: ConvertAPIToDB
    from: UserAPI
    to: UserDB
    fields:
      - from: ID
        to: ID
        transform: "strconv.Atoi(from)"

实际应用场景

  1. 数据库模型与API模型转换
  2. 不同版本API之间的兼容层
  3. 领域模型与持久化模型转换
  4. ProtoBuf/GRPC消息与内部模型转换

优势

  1. 类型安全:生成的代码是类型安全的,编译时就能发现错误
  2. 减少样板代码:自动生成重复的类型转换代码
  3. 易于维护:当模型变更时,只需重新生成代码
  4. 高性能:生成的代码是直接的赋值操作,没有反射开销

注意事项

  1. 生成的代码应该被检入版本控制
  2. 在CI流程中加入代码生成步骤,确保生成的代码是最新的
  3. 对于复杂转换逻辑,可以结合自定义函数使用

CopyGen通过自动化这些重复的模式转换工作,可以显著提高开发效率,同时减少人为错误的可能性。

回到顶部