欢迎加入开源鸿蒙PC社区: https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目https://atomgit.com/OpenHarmonyPCDeveloper
AtomGit 仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_go_cgo

本文讲解鸿蒙PC基于musl库、应用沙箱与二进制强制签名机制,不原生支持Go语言,通用Linux编译产物无法直接运行。需借助社区Harmonybrew包管理器搭建开发环境:纯Go开发安装go与ohos-sdk,依托SDK实现编译自动签名;CGO跨语言开发需额外安装llvm-gcc-compat补齐cc 编译命令,编译时手动开启CGO参数。搭配CodeArts IDE可完成全流程开发,同时需提前处理软件冲突、使用原生终端规避环境报错。

可以参考OpenHarmony 鸿蒙 PC + CodeArts IDE 实现 Go开发完整开发环境搭建指南


一、copier 是什么

github.com/jinzhu/copier 是 Go 结构体自动复制映射库。
日常开发经常需要:实体结构体 ↔ DTO/VO/分页输出结构体,手动逐个字段赋值代码冗余、容易漏字段、改结构体就要同步改复制逻辑;
copier 自动根据字段名匹配复制值,支持同名字段、忽略字段、指定映射、切片批量复制、嵌套结构体复制。

核心作用

  1. 结构体之间自动拷贝同名字段(string/int/bool/time/嵌套struct全部支持)
  2. 支持数组/切片批量复制([]User → []UserVO)
  3. 支持忽略指定字段、自定义字段映射、覆盖值
  4. 支持深拷贝嵌套结构体,不用手动递归赋值
  5. 适用于:数据库Model → 返回前端VO、入参DTO → 数据库Model转换

安装

go env -w GOPROXY=https://goproxy.cn,direct
go mod init copier-demo
go get github.com/jinzhu/copier

请添加图片描述

完整无报错 main.go

package main

import (
	"fmt"
	"github.com/jinzhu/copier"
	"time"
)

// UserModel 数据库源结构体
type UserModel struct {
	ID       uint
	Username string
	Phone    string
	Age      int
	Balance  float64
	CreateAt time.Time
	Password string // 敏感密码,不需要复制到VO
}

// UserVO 返回前端目标结构体
// copier:"-" 代表此字段不参与复制
type UserVO struct {
	ID       uint
	Username string
	Phone    string
	Age      int
	Balance  float64
	CreateAt string
	Password string `copier:"-"` // 忽略此字段复制
}

// 嵌套结构体示例
type OrderModel struct {
	OrderID string
	UID     uint
	Price   float64
	User    UserModel
}

type OrderVO struct {
	OrderID string
	UID     uint
	Price   float64
	User    UserVO
}

func main() {
	// 1. 单个结构体 Model -> VO 基础复制
	fmt.Println("===== 单个结构体复制 =====")
	model := UserModel{
		ID:       1001,
		Username: "lisi",
		Phone:    "13800138000",
		Age:      24,
		Balance:  199.99,
		CreateAt: time.Now(),
		Password: "abc123456",
	}
	var vo UserVO
	// 仅使用合法选项:DeepCopy深拷贝,无Ignore
	err := copier.CopyWithOption(&vo, &model, copier.Option{
		DeepCopy: true,
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("转换后VO:%+v\n", vo)

	// 2. 切片批量复制 []Model → []VO
	fmt.Println("\n===== 切片批量复制 =====")
	modelList := []UserModel{
		{ID: 1, Username: "zhangsan", Phone: "13800000001", Age: 20, CreateAt: time.Now()},
		{ID: 2, Username: "wangwu", Phone: "13800000002", Age: 26, CreateAt: time.Now()},
	}
	var voList []UserVO
	err = copier.Copy(&voList, &modelList)
	if err != nil {
		panic(err)
	}
	for _, item := range voList {
		fmt.Printf("列表VO:%+v\n", item)
	}

	// 3. 嵌套结构体复制
	fmt.Println("\n===== 嵌套结构体复制 =====")
	orderModel := OrderModel{
		OrderID: "ORD001",
		UID:     1001,
		Price:   299.0,
		User:    model,
	}
	var orderVO OrderVO
	err = copier.CopyWithOption(&orderVO, &orderModel, copier.Option{
		DeepCopy: true,
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("嵌套订单VO:%+v\n", orderVO)

	// 4. IgnoreEmpty 示例:只复制非空字段,不覆盖目标原有值
	fmt.Println("\n===== 忽略源空值复制(IgnoreEmpty) =====")
	oldVO := UserVO{ID: 999, Username: "oldName", CreateAt: "2025-01-01"}
	// IgnoreEmpty=true 源零值不会覆盖目标已有数据
	err = copier.CopyWithOption(&oldVO, &model, copier.Option{
		DeepCopy:    true,
		IgnoreEmpty: true,
	})
	fmt.Printf("IgnoreEmpty复制后:%+v\n", oldVO)
}

请添加图片描述

运行

go run main.go

copier 是 Go 后端最常用的结构体映射复制工具,核心场景:数据库 Model ↔ 前端 VO/DTO 转换、切片批量复制、嵌套结构体递归拷贝,自动匹配同名字段,支持忽略字段、深拷贝、空值忽略等能力,省去手动逐个字段赋值样板代码。


一、库简介

github.com/jinzhu/copier 是Go开发最常用的结构体转换工具,专门解决数据库Model ↔ 前端VO/DTO 对象拷贝,替代手动逐个字段赋值,支持:普通结构体、切片批量复制、嵌套结构体、忽略字段、忽略空值、深拷贝等能力。
安装依赖:

go get github.com/jinzhu/copier

二、头部导入

package main

import (
	"fmt"
	"github.com/jinzhu/copier"
	"time"
)
  • fmt:打印输出
  • copier:对象拷贝核心库
  • time:时间类型,演示结构体时间字段自动转字符串

三、结构体定义解析

1. 单层用户 Model & VO

// UserModel 数据库源结构体
type UserModel struct {
	ID       uint
	Username string
	Phone    string
	Age      int
	Balance  float64
	CreateAt time.Time
	Password string // 敏感密码,不需要复制到VO
}

// UserVO 返回前端目标结构体
// copier:"-" 代表此字段不参与复制
type UserVO struct {
	ID       uint
	Username string
	Phone    string
	Age      int
	Balance  float64
	CreateAt string
	Password string `copier:"-"` // 忽略此字段复制
}
  1. Model:数据库映射实体,包含完整字段、密码、time.Time 时间类型
  2. VO:给前端返回的视图对象,剔除敏感字段、类型适配(time.Time → string)
  3. 标签 copier:"-":标记该字段跳过拷贝,源对象Password不会赋值到VO,防止密码泄露

2. 嵌套结构体 OrderModel / OrderVO

type OrderModel struct {
	OrderID string
	UID     uint
	Price   float64
	User    UserModel // 嵌套Model
}

type OrderVO struct {
	OrderID string
	UID     uint
	Price   float64
	User    UserVO // 嵌套VO
}

copier 自动识别嵌套结构体,递归完成内部子结构体转换,无需手动单独拷贝User。

四、main 四大场景代码拆解

场景1:单个结构体 Model → VO 基础深拷贝

model := UserModel{
	ID:       1001,
	Username: "lisi",
	Phone:    "13800138000",
	Age:      24,
	Balance:  199.99,
	CreateAt: time.Now(),
	Password: "abc123456",
}
var vo UserVO
// 仅使用合法选项:DeepCopy深拷贝,无Ignore
err := copier.CopyWithOption(&vo, &model, copier.Option{
	DeepCopy: true,
})
if err != nil {
	panic(err)
}
fmt.Printf("转换后VO:%+v\n", vo)
核心API说明
  1. copier.Copy(dst, src):基础拷贝函数
  2. copier.CopyWithOption(dst, src, option):带自定义配置拷贝
  3. DeepCopy: true:开启深拷贝,指针、嵌套结构体、切片不会共用底层内存,修改VO不会影响原Model
  4. 自动类型转换:源 time.Time 自动转为VO的 string 字符串时间
  5. Password 带 copier:"-",VO.Password 保持空字符串,不会复制密码

场景2:切片批量复制 []Model → []VO

modelList := []UserModel{
	{ID: 1, Username: "zhangsan", Phone: "13800000001", Age: 20, CreateAt: time.Now()},
	{ID: 2, Username: "wangwu", Phone: "13800000002", Age: 26, CreateAt: time.Now()},
}
var voList []UserVO
err = copier.Copy(&voList, &modelList)
if err != nil {
	panic(err)
}
for _, item := range voList {
	fmt.Printf("列表VO:%+v\n", item)
}

支持切片直接批量转换,不用循环遍历逐个拷贝,查询数据库列表后一键转前端返回数组,大幅简化代码。

场景3:嵌套结构体自动递归拷贝

orderModel := OrderModel{
	OrderID: "ORD001",
	UID:     1001,
	Price:   299.0,
	User:    model,
}
var orderVO OrderVO
err = copier.CopyWithOption(&orderVO, &orderModel, copier.Option{
	DeepCopy: true,
})

无需手动处理内部 User,copier 自动识别内部结构体,将 UserModel 完整转换为 UserVO,多层嵌套同样支持递归拷贝。

场景4:IgnoreEmpty 忽略源空值,不覆盖目标原有数据

oldVO := UserVO{ID: 999, Username: "oldName", CreateAt: "2025-01-01"}
// IgnoreEmpty=true 源零值不会覆盖目标已有数据
err = copier.CopyWithOption(&oldVO, &model, copier.Option{
	DeepCopy:    true,
	IgnoreEmpty: true,
})
fmt.Printf("IgnoreEmpty复制后:%+v\n", oldVO)
  • IgnoreEmpty: true:如果源结构体字段是零值(空字符串、0、nil),不会覆盖目标对象已存在的值
  • 适用场景:表单局部更新,只传部分字段,保留原有未修改字段

五、核心标签与配置参数汇总

1. 结构体标签

  • copier:"-":忽略此字段,不参与拷贝
  • copier:"TargetFieldName":字段名不一致时手动映射,例 Name string copier:“UserName”`

2. Option 常用配置

参数 作用
DeepCopy 开启深拷贝,嵌套/指针推荐开启
IgnoreEmpty 源零值不覆盖目标字段
IgnoreNil 源nil指针不覆盖目标

六、运行输出关键特征

  1. VO 的 Password 为空,密码不会复制;
  2. CreateAt 从 time.Time 自动转为字符串时间;
  3. 嵌套订单VO内User已经完成Model转VO;
  4. IgnoreEmpty场景下,oldVO原有旧字段不会被源零值覆盖。

七、项目使用优势与注意事项

优势

  1. 省去大量手动字段赋值代码,减少重复工作量;
  2. 自动兼容基础类型转换、时间类型、切片、嵌套结构体;
  3. 支持敏感字段忽略、局部更新忽略空值,适配CRUD业务;
  4. API简洁,单函数完成单条/批量转换。

生产注意点

  1. 涉及嵌套、指针结构体务必开启 DeepCopy: true,避免浅拷贝数据互相污染;
  2. 密码、身份证等敏感字段必须添加 copier:"-" 禁止拷贝到返回VO;
  3. 字段名不一致时使用映射标签手动绑定;
  4. 拷贝后建议捕获err,示例中panic仅用于演示,线上改为日志打印错误。

一、安装依赖

go get github.com/jinzhu/copier

导入依赖:

import (
	"fmt"
	"github.com/jinzhu/copier"
	"time"
)

二、结构体定义分层说明(后端标准分层思想)

1. UserModel 数据库实体(Model)

从数据库查询出来的原始结构体,包含完整字段、敏感字段、原生 time.Time 时间类型

type UserModel struct {
	ID       uint
	Username string
	Phone    string
	Age      int
	Balance  float64
	CreateAt time.Time // 原生时间类型
	Password string    // 敏感密码,不能返回前端
}

2. UserVO 前端返回视图对象(VO)

对外接口返回给前端的结构体:

  1. 移除敏感字段逻辑:同名字段上标记 copier:"-" 直接跳过复制
  2. 类型转换需求:time.Timestring 字符串时间,copier 自动兼容基础类型转换
type UserVO struct {
	ID       uint
	Username string
	Phone    string
	Age      int
	Balance  float64
	CreateAt string // 字符串,适配前端
	Password string `copier:"-"` // tag标记:复制时忽略此字段
}
  • Tag copier:"-" 核心作用:即使源结构体存在同名字段,也不复制该值,专门用于密码、密钥、内部ID等敏感信息脱敏。

3. 嵌套结构体 OrderModel / OrderVO

模拟业务一对一场景:订单内嵌套用户信息

type OrderModel struct {
	OrderID string
	UID     uint
	Price   float64
	User    UserModel // 嵌套数据库实体
}

type OrderVO struct {
	OrderID string
	UID     uint
	Price   float64
	User    UserVO // 嵌套前端VO
}

copier 开启 DeepCopy: true 后会递归自动复制内部嵌套结构体,不用手动单独拷贝内层 User。

三、核心API区分

  1. copier.Copy(dst, src)
    基础浅拷贝,自动匹配同名字段,适合简单结构体、切片批量复制,无自定义配置。
  2. copier.CopyWithOption(dst, src, copier.Option{})
    带自定义配置拷贝,支持深拷贝、忽略空值、字段映射等高级功能。
  3. 入参规则:第一个参数目标结构体指针,第二个源结构体指针

四、分模块逐代码解析

模块1:单个结构体 Model → VO 基础深拷贝

model := UserModel{
	ID:       1001,
	Username: "lisi",
	Phone:    "13800138000",
	Age:      24,
	Balance:  199.99,
	CreateAt: time.Now(),
	Password: "abc123456",
}
var vo UserVO
err := copier.CopyWithOption(&vo, &model, copier.Option{
	DeepCopy: true,
})
if err != nil {
	panic(err)
}
fmt.Printf("转换后VO:%+v\n", vo)
关键配置 DeepCopy: true 深拷贝
  • 浅拷贝默认:只复制基础数据类型(int/string/float),引用类型(切片、map、嵌套结构体)只复制内存地址,内外结构体修改会互相影响。
  • 深拷贝:完整递归复制所有嵌套数据,生成全新独立内存,修改 VO 不会影响原 Model,业务开发推荐始终开启
自动执行逻辑
  1. 匹配所有同名字段:ID、Username、Phone、Age、Balance 直接复制;
  2. CreateAttime.Time 自动转为 VO 的 string
  3. Password 标记 copier:"-",完全跳过,VO.Password 保持空字符串;
  4. 敏感密码不会暴露给前端,完美实现脱敏。

模块2:切片批量复制 []Model → []VO

modelList := []UserModel{
	{ID: 1, Username: "zhangsan", Phone: "13800000001", Age: 20, CreateAt: time.Now()},
	{ID: 2, Username: "wangwu", Phone: "13800000002", Age: 26, CreateAt: time.Now()},
}
var voList []UserVO
err = copier.Copy(&voList, &modelList)
if err != nil {
	panic(err)
}
for _, item := range voList {
	fmt.Printf("列表VO:%+v\n", item)
}
核心优势

不用手写 for 循环逐个 new VO、赋值字段,一行代码完成整个切片批量转换。
适用场景:数据库分页查询列表,批量转接口返回VO数组。

模块3:嵌套结构体递归拷贝

orderModel := OrderModel{
	OrderID: "ORD001",
	UID:     1001,
	Price:   299.0,
	User:    model,
}
var orderVO OrderVO
err = copier.CopyWithOption(&orderVO, &orderModel, copier.Option{
	DeepCopy: true,
})
fmt.Printf("嵌套订单VO:%+v\n", orderVO)

开启 DeepCopy 后自动递归处理内部 User 嵌套结构:

  1. 外层 OrderID、UID、Price 直接复制;
  2. 内层 User(UserModel) 自动完整拷贝到 User(UserVO)
  3. 内层 Password 同样遵循 copier:"-" 忽略规则。
    不开启深拷贝时嵌套结构体只会拷贝指针,数据不隔离,极易产生副作用。

模块4:IgnoreEmpty 忽略源空值,不覆盖目标原有数据

oldVO := UserVO{ID: 999, Username: "oldName", CreateAt: "2025-01-01"}
err = copier.CopyWithOption(&oldVO, &model, copier.Option{
	DeepCopy:    true,
	IgnoreEmpty: true,
})
fmt.Printf("IgnoreEmpty复制后:%+v\n", oldVO)
IgnoreEmpty: true 作用规则

源结构体中零值/空值字段不会覆盖目标结构体已存在的值:

  • 源 model.ID=1001(非空)→ 覆盖 oldVO.ID=999;
  • 如果源某个字段为空(如源 Phone=“”),则不会修改 oldVO 原有 Phone;
业务场景

局部更新接口:只传部分字段更新,保留前端原有未传字段数据,避免被空值清空。

五、补充常用 Tag 拓展(示例只用到 copier:"-",完整常用标签)

  1. copier:"-":忽略此字段,不复制
  2. copier:"sourceFieldName":字段名不一致手动映射
type UserVO struct {
	UserID uint `copier:"ID"` // 源字段ID → 目标UserID
}
  1. copier:"rename" 批量统一命名转换,配合数据库下划线、前端驼峰使用

六、Option 完整配置字段说明

copier.Option{
    DeepCopy:    true,  // 开启深拷贝,推荐必开
    IgnoreEmpty: true,  // 源空值不覆盖目标
    IgnoreZero:  true,  // 数字0、空字符串都视为空值忽略
    FieldMapper: map[string]string{}, // 全局字段映射
}

七、业务开发核心价值总结

  1. 消除样板代码:不用手动写几十行 vo.Name = model.Name
  2. 分层解耦:Model 存库、VO 返回前端,敏感字段一键脱敏;
  3. 批量处理:切片数组一键转换,分页列表开发效率极高;
  4. 嵌套支持:自动递归复制嵌套结构体,适配订单、详情等复杂业务;
  5. 灵活控制:支持忽略空值、自定义字段映射,适配更新接口、特殊字段转换;
  6. 类型自动适配:time.Time ↔ string、int ↔ uint 等基础类型自动转换。

八、常见注意事项

  1. 传参必须传指针,否则拷贝不会生效;
  2. 嵌套结构体、切片、map 场景务必开启 DeepCopy,防止引用共享;
  3. 密码、token、内部主键一律用 copier:"-" 屏蔽,防止接口泄露;
  4. IgnoreEmpty 适合局部更新,查询列表场景一般关闭,需要完整覆盖目标结构体。

核心API说明

  1. copier.Copy(dst, src)
    基础复制,自动匹配同名字段,支持结构体、切片。
  2. copier.CopyWithOption(dst, src, copier.Option{})
    带配置复制,常用配置:
  • Ignore []string:忽略字段,支持嵌套 User.Password
  • DeepCopy: true:开启深拷贝,修改源不影响目标
  1. 规则
  • 字段名完全匹配才复制(大小写一致)
  • time.Time 会自动转字符串填入string字段
  • 数字类型自动兼容转换(uint/int/float64)
  • 嵌套结构体自动递归复制

业务场景

  1. ORM查询出来的数据库Model,快速转为给前端返回的VO,不用手动赋值几十行代码
  2. 批量列表转换,不用循环逐个赋值
  3. DTO入参复制到数据库保存Model
  4. 多层嵌套实体转换,简化嵌套赋值逻辑
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐