llvm-gcc-compat补齐cc 编译命令实现鸿蒙PC安装第三方库copier,玩转go语言结构体自动复制映射库
欢迎加入开源鸿蒙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 自动根据字段名匹配复制值,支持同名字段、忽略字段、指定映射、切片批量复制、嵌套结构体复制。
核心作用
- 结构体之间自动拷贝同名字段(string/int/bool/time/嵌套struct全部支持)
- 支持数组/切片批量复制([]User → []UserVO)
- 支持忽略指定字段、自定义字段映射、覆盖值
- 支持深拷贝嵌套结构体,不用手动递归赋值
- 适用于:数据库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:"-"` // 忽略此字段复制
}
- Model:数据库映射实体,包含完整字段、密码、
time.Time时间类型 - VO:给前端返回的视图对象,剔除敏感字段、类型适配(
time.Time→ string) - 标签
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说明
copier.Copy(dst, src):基础拷贝函数copier.CopyWithOption(dst, src, option):带自定义配置拷贝DeepCopy: true:开启深拷贝,指针、嵌套结构体、切片不会共用底层内存,修改VO不会影响原Model- 自动类型转换:源
time.Time自动转为VO的string字符串时间 - 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 stringcopier:“UserName”`
2. Option 常用配置
| 参数 | 作用 |
|---|---|
| DeepCopy | 开启深拷贝,嵌套/指针推荐开启 |
| IgnoreEmpty | 源零值不覆盖目标字段 |
| IgnoreNil | 源nil指针不覆盖目标 |
六、运行输出关键特征
- VO 的 Password 为空,密码不会复制;
- CreateAt 从 time.Time 自动转为字符串时间;
- 嵌套订单VO内User已经完成Model转VO;
- IgnoreEmpty场景下,oldVO原有旧字段不会被源零值覆盖。
七、项目使用优势与注意事项
优势
- 省去大量手动字段赋值代码,减少重复工作量;
- 自动兼容基础类型转换、时间类型、切片、嵌套结构体;
- 支持敏感字段忽略、局部更新忽略空值,适配CRUD业务;
- API简洁,单函数完成单条/批量转换。
生产注意点
- 涉及嵌套、指针结构体务必开启
DeepCopy: true,避免浅拷贝数据互相污染; - 密码、身份证等敏感字段必须添加
copier:"-"禁止拷贝到返回VO; - 字段名不一致时使用映射标签手动绑定;
- 拷贝后建议捕获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)
对外接口返回给前端的结构体:
- 移除敏感字段逻辑:同名字段上标记
copier:"-"直接跳过复制 - 类型转换需求:
time.Time→string字符串时间,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区分
copier.Copy(dst, src)
基础浅拷贝,自动匹配同名字段,适合简单结构体、切片批量复制,无自定义配置。copier.CopyWithOption(dst, src, copier.Option{})
带自定义配置拷贝,支持深拷贝、忽略空值、字段映射等高级功能。- 入参规则:第一个参数目标结构体指针,第二个源结构体指针。
四、分模块逐代码解析
模块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,业务开发推荐始终开启。
自动执行逻辑
- 匹配所有同名字段:ID、Username、Phone、Age、Balance 直接复制;
CreateAt源time.Time自动转为 VO 的string;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)
}
核心优势
不用手写 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 嵌套结构:
- 外层 OrderID、UID、Price 直接复制;
- 内层
User(UserModel)自动完整拷贝到User(UserVO); - 内层 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:"-",完整常用标签)
copier:"-":忽略此字段,不复制copier:"sourceFieldName":字段名不一致手动映射
type UserVO struct {
UserID uint `copier:"ID"` // 源字段ID → 目标UserID
}
copier:"rename"批量统一命名转换,配合数据库下划线、前端驼峰使用
六、Option 完整配置字段说明
copier.Option{
DeepCopy: true, // 开启深拷贝,推荐必开
IgnoreEmpty: true, // 源空值不覆盖目标
IgnoreZero: true, // 数字0、空字符串都视为空值忽略
FieldMapper: map[string]string{}, // 全局字段映射
}
七、业务开发核心价值总结
- 消除样板代码:不用手动写几十行
vo.Name = model.Name; - 分层解耦:Model 存库、VO 返回前端,敏感字段一键脱敏;
- 批量处理:切片数组一键转换,分页列表开发效率极高;
- 嵌套支持:自动递归复制嵌套结构体,适配订单、详情等复杂业务;
- 灵活控制:支持忽略空值、自定义字段映射,适配更新接口、特殊字段转换;
- 类型自动适配:time.Time ↔ string、int ↔ uint 等基础类型自动转换。
八、常见注意事项
- 传参必须传指针,否则拷贝不会生效;
- 嵌套结构体、切片、map 场景务必开启
DeepCopy,防止引用共享; - 密码、token、内部主键一律用
copier:"-"屏蔽,防止接口泄露; IgnoreEmpty适合局部更新,查询列表场景一般关闭,需要完整覆盖目标结构体。
核心API说明
copier.Copy(dst, src)
基础复制,自动匹配同名字段,支持结构体、切片。copier.CopyWithOption(dst, src, copier.Option{})
带配置复制,常用配置:
Ignore []string:忽略字段,支持嵌套User.PasswordDeepCopy: true:开启深拷贝,修改源不影响目标
- 规则
- 字段名完全匹配才复制(大小写一致)
- time.Time 会自动转字符串填入string字段
- 数字类型自动兼容转换(uint/int/float64)
- 嵌套结构体自动递归复制
业务场景
- ORM查询出来的数据库Model,快速转为给前端返回的VO,不用手动赋值几十行代码
- 批量列表转换,不用循环逐个赋值
- DTO入参复制到数据库保存Model
- 多层嵌套实体转换,简化嵌套赋值逻辑
更多推荐



所有评论(0)