golang Copier 数据复制

Copier

I am a copier, I copy everything from one to another

Copier是golang实现的,实现不同数据结构之间数据复制的工具包

github地址

使用方法

以User和Employee之间相互复制为例
使用的版本为 v0.3.5

入门

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	var employee = Employee{}

	// 从user把数据复制到employee中
	err := copier.Copy(&employee, user)

	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// main.Employee{Name:"Jinzhu", Age:18, Salary:200000}

toValue 传参必须为指针

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	// 正确用法
	// err := copier.Copy(&employee, user)
	err := copier.Copy(employee, user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// copy destination is invalid

结构体之间相互复制,默认以字段名作为映射

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}
// 结果:main.Employee{Name:"Jinzhu", Age:18, Salary:200000}

如果字段名不相同,则不会进行字段值复制,但是不会影响其他字段值复制

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Title  string
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// 结果:main.Employee{Title:"", Age:18, Salary:200000}

如果字段名不相同的字段值想进行复制,可以通过标签进行映射

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Title  string `copier:"Name"`
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// 结果:main.Employee{Title:"Jinzhu", Age:18, Salary:200000}

copier 标签字段名必须是首字母大写

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Title  string `copier:"name"`
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// copier field name tag must be start upper case

相互映射的字段,数据类型要尽量相同,否则会出现意想不到的结果

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Title  int `copier:"Name"`
	Age    string
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// main.Employee{Title:0, Age:"\x12", Salary:200000}

支持通过同样的名字实现method给field赋值

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

func (receiver User) Title() string {
	return "Golang " + receiver.Name
}

type Employee struct {
	Title  string
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// User.Title() 给 Employee.Title 赋值
// main.Employee{Title:"Golang Jinzhu", Age:18, Salary:200000}

支持通过同样的名字实现field给method赋值

method必须有唯一的形参,形参的数据类型跟field要一致

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Title  string
	Age    int32
	Salary int
}

// 复制失败
//func (receiver *Employee) Name(name string, age int) {
//	receiver.Title = "Title " + name
//}

// 复制失败
//func (receiver *Employee) Name() {
//	receiver.Title = "Title " + name
//}

func (receiver *Employee) Name(name string) {
	receiver.Title = "Title " + name
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// main.Employee{Title:"Title Jinzhu", Age:18, Salary:200000}

must 标签

must 标签用来指定toValue.field 必须有相应的 fromValue.field ,否则会报错

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Title  string `copier:"must"`
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// panic: Field Title has must tag but was not copied

忽略指定字段

通过标签 copier:"-"来标识字段要跳过字段值复制,而且只有标识在toValue字段上才会生效

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string `copier:"-"`
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// main.Employee{Name:"", Age:18, Salary:200000}

nopanic 标签

nopanic 用来告诉copier ,指定字段出现异常,通过返回error方式报错,而不是通过panic方式报错

当前的版本,源代码在返回error后,并没有对外抛出,所以当前的效果是,不抛panic,也不返回error
在这里插入图片描述

在这里插入图片描述

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Title  string `copier:"must,nopanic"`
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	employee := Employee{}
	err := copier.Copy(&employee, &user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// main.Employee{Title:"", Age:18, Salary:200000}

结构体批量复制

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string
	Age    int32
	Salary int
}

func main() {
	users := []User{
		{
			Name:   "Jinzhu",
			Age:    18,
			Salary: 200000,
		},
		{
			Name:   "Jinzhu1",
			Age:    20,
			Salary: 180000,
		},
	}
	var employee []Employee
	err := copier.Copy(&employee, users)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// []main.Employee{main.Employee{Name:"Jinzhu", Age:18, Salary:200000}, main.Employee{Name:"Jinzhu1", Age:20, Salary:180000}}

结构体复制到结构体列表

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string
	Age    int32
	Salary int
}

func main() {
	users := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	var employee []Employee
	err := copier.Copy(&employee, users)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// []main.Employee{main.Employee{Name:"Jinzhu", Age:18, Salary:200000}}

map To map 复制


package main

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

func main() {
	user := map[string]interface{}{
		"name":   "Jinzhu",
		"age":    18,
		"salary": 200000,
	}
	var employee = map[string]interface{}{}
	err := copier.Copy(&employee, user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// map[string]interface {}{"age":18, "name":"Jinzhu", "salary":200000}

CopyWithOption 使用

CopyWithOption 支持调用时传参选择项,来影响copier的行为

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "Jinzhu",
		Age:    18,
		Salary: 200000,
	}
	var employee = Employee{
		Name: "Jinzhu-Name",
	}
	err := copier.CopyWithOption(&employee, user, copier.Option{})
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// main.Employee{Name:"Jinzhu", Age:18, Salary:200000}

IgnoreEmpty选项

IgnoreEmpty 选项用来指定是否跳过空值

package main

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

type User struct {
	Name   string
	Age    int32
	Salary int
}

type Employee struct {
	Name   string
	Age    int32
	Salary int
}

func main() {
	user := User{
		Name:   "",
		Age:    18,
		Salary: 200000,
	}
	var employee = Employee{
		Name: "Jinzhu-Name",
	}
	err := copier.CopyWithOption(&employee, user, copier.Option{IgnoreEmpty: true})
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", employee)
	}
}

// main.Employee{Name:"Jinzhu-Name", Age:18, Salary:200000}
Converters 选项

Converters 选项用来自定义转换方式

package main

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

type User struct {
	Name     string
	Age      int32
	Salary   int
	Birthday time.Time
}

type Employee struct {
	Name     string
	Age      int32
	Salary   int
	Birthday string
}

func main() {
	user := User{
		Name:     "Jinzhu",
		Age:      18,
		Salary:   200000,
		Birthday: time.Now(),
	}
	var employee = Employee{
		Name: "Jinzhu-Name",
	}
	err := copier.CopyWithOption(&employee, user, copier.Option{IgnoreEmpty: true, Converters: []copier.TypeConverter{
		{
			SrcType: time.Time{},
			DstType: "",
			Fn: func(src interface{}) (interface{}, error) {
				srcTime, ok := src.(time.Time)
				if !ok {
					return "", nil
				}
				return srcTime.Format("2006-01-02 15:04:05"), nil
			},
		},
	}})

	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%#v \n", user)
		fmt.Printf("%#v \n", employee)
	}
}

// main.User{Name:"Jinzhu", Age:18, Salary:200000, Birthday:time.Date(2023, time.November, 12, 20, 48, 47, 73860000, time.Local)}
// main.Employee{Name:"Jinzhu", Age:18, Salary:200000, Birthday:"2023-11-12 20:48:47"}
DeepCopy 选项
待补充

总结

整体来说,copier能满足我们日常业务开发中的大部分场景,而且可以有效的解耦数据结构之间的依赖,通过一种低耦合的方式,实现数据复制任务

附:本文只是简单总结了copier的使用方式,不足之处希望能多多提意见

——结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/136465.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DevChat 初探之 RBAC 模型的实现

今天我们来尝试一款编程辅助助手 DevChat, 看能不能提升咱们的日常编程效率。作为一款编程助手,我们来看看它与 Copilot, CodeWhisperer 同领域产品的一些区别和特色。定个小目标,通过 DevChat 实现一个简单的 RBAC 模型,小试牛刀一下&#x…

Acer宏碁Aspire A715-75G笔记本工厂模式原厂Windows10预装OEM系统2004带恢复功能

下载链接:https://pan.baidu.com/s/1nJFd25lElc1VAPf_RqSDYA?pwdd05h 提取码:d05h 原装出厂系统自带所有驱动、Office办公软件、出厂主题壁纸、系统属性Acer宏基专属的LOGO标志、 Acer Care Center、Quick Access等预装程序 所需要工具&#xff1a…

kubenetes-kubelet组件

一、kubelet架构 每个节点都运行一个kubelet进程,默认监听10250端口,kubelet作用非常重要,是节点的守护神。 接收并执行 master发来的指令。管理Pod及Pod中的容器。每个kubelet进程会在API Server 上注册节点自身信息,定期向mast…

mysql讲解2 之事务 索引 以及权限等

系列文章目录 mysql 讲解一 博客链接 点击此处即可 文章目录 系列文章目录一、事务1.1 事务的四个原则1.2 脏读 不可重复读 幻读 二、索引三,数据库用户管理四、mysql备份 一、事务 1.1 事务的四个原则 什么是事务 事务就是将一组SQL语句放在同一批次内去执行 如果一个SQ…

常见后缀名总结 为你指点迷津

相信在日常的学习和工作中,大家一定会遇到各种各样的文件类型,他们的后缀名类型各不相同,诸多陌生的文件格式经常让大家不知道他们存在于电脑的意义,想删又没法删,想执行又无法执行。 今天,学长就带领大家一…

笔记:AI量化策略开发流程-基于BigQuant平台(二)

五、模型训练股票预测 完成了数据处理,接下来就可利用平台集成的各算法进行模型训练和模型预测啦。本文将详细介绍“模型训练”、“模型预测”两大模块操作、原理。 模型训练和模型预测是AI策略区别于传统量化策略的核心,我们通过模型训练模块利用训练…

c语言练习11周(6~10)

输入任意字串&#xff0c;将串中除了首尾字符的其他字符升序排列显示&#xff0c;串中字符个数最多20个。 题干 输入任意字串&#xff0c;将串中除了首尾字符的其他字符升序排列显示&#xff0c;串中字符个数最多20个。输入样例gfedcba输出样例gbcdefa 选择排序 #include<s…

每日一题(LeetCode)----数组--长度最小的子数组

每日一题(LeetCode)----数组–长度最小的子数组 1.题目&#xff08; 209.长度最小的子数组&#xff09; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &…

深度解析找不到msvcp120.dll相关问题以及解决方法

​在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp120.dll丢失”。这个错误通常会导致某些应用程序无法正常运行&#xff0c;给用户带来很大的困扰。那么&#xff0c;如何解决msvcp120.dll丢失的问题呢&#xff1f;本文将为大家介绍…

手机地磁传感器与常见问题

在手机中&#xff0c;存在不少传感器&#xff0c;例如光距感&#xff0c;陀螺仪&#xff0c;重力加速度&#xff0c;地磁等。关于各传感器&#xff0c;虽功能作用大家都有所了解&#xff0c;但是在研发设计debug过程中&#xff0c;却总是会遇到很多头疼的问题。关于传感器&…

BM65 最长公共子序列(二)

动态规划 BM65 最长公共子序列&#xff08;二&#xff09; 这道题是动态规划的典型例题。 思路 题目要求获取最长公共子序列&#xff0c;我们要先求最长公共子序列的长度&#xff0c;然后根据这个长度倒推从而获取这个子序列。注意&#xff1a;子序列不是子串&#xff0c;子…

C语言进阶

数组 在基础篇说过&#xff0c;数组实际上是构造类型之一&#xff0c;是连续存放的。 一维数组 定义 定义格式&#xff1a;[存储类型] 数据类型 数组名标识符[下标]; 下面分模块来介绍一下数组的定义部分的内容。 1、初始化和元素引用&#xff1a; 可以看到数组是连续存储…

第六章 DNS域名解析服务器

1、DNS简介 DNS&#xff08;Domain Name System&#xff09;是互联网上的一项服务&#xff0c;它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网。 DNS系统使用的是网络的查询&#xff0c;那么自然需要有监听的port。DNS使用的是53端口…

【Python】python读取,显示,保存图像的几种方法

一、PIL&#xff1a;Python Imaging Library&#xff08;pillow&#xff09; PIL读取图片不直接返回numpy对象&#xff0c;可以用numpy提供的函数np.array()进行转换&#xff0c;亦可用Image.fromarray()再从numpy对象转换为原来的Image对象&#xff0c;读取&#xff0c;显示&…

【OpenCV实现图像:用OpenCV图像处理技巧之白平衡算法2】

文章目录 概要Gray-world AlgotithmGround Truth Algorithm结论&#xff1a; 概要 随着数字图像处理技术的不断发展&#xff0c;白平衡算法成为了图像处理中一个关键的环节。白平衡的目标是校正图像中的颜色偏差&#xff0c;使得白色在图像中呈现真实的白色&#xff0c;从而提…

transfomer模型——简介,代码实现,重要模块解读,源码,官方

一、什么是transfomer Transformer是一种基于注意力机制&#xff08;attention mechanism&#xff09;的神经网络架构&#xff0c;最初由Vaswani等人在论文《Attention Is All You Need》中提出。它在自然语言处理&#xff08;NLP&#xff09;领域取得了巨大成功&#xff0c;特…

虚拟机CentOS 8 重启后不能上网

情况说明&#xff1a;原本虚拟机是可以上网的&#xff0c;然后嘚一下&#xff0c;重启后&#xff0c;连接不上网络&#xff0c;完了&#xff0c;上网查找一堆质料&#xff0c;我的连接方式是桥接模式&#xff08;复制物理网络连接状态&#xff09;。 好&#xff0c;有人说是vmn…

Git基本概念和使用方式

Git 是一种版本控制系统&#xff0c;用于管理文件版本的变化。以下是其基本概念和使用方式&#xff1a; 仓库&#xff08;repository&#xff09;&#xff1a;Git 存储代码的地方&#xff0c;可以理解为一个项目的文件夹。提交&#xff08;commit&#xff09;&#xff1a;Git …

【Go入门】struct类型

【Go入门】struct类型 struct Go语言中&#xff0c;也和C或者其他语言一样&#xff0c;我们可以声明新的类型&#xff0c;作为其它类型的属性或字段的容器。例如&#xff0c;我们可以创建一个自定义类型person代表一个人的实体。这个实体拥有属性&#xff1a;姓名和年龄。这样…

前端开发引入element plus与windi css

背景 前端开发有很多流行框架&#xff0c;像React 、angular、vue等等&#xff0c;本文主要讲vue 给新手用的教程&#xff0c;其实官网已经写的很清楚&#xff0c;这里再啰嗦只是为了给新手提供一个更加简单明了的参考手册。 一、打开element plus官网选则如图所示模块安装命令…