gf框架提供了非常强大的类型转换包gconv,可以实现将任何数据类型转换为指定的数据类型,对常用基本数据类型之间的无缝转换,同时也支持任意类型到struct对象的属性赋值。由于gconv模块内部大量使用了断言而非反射(仅struct转换使用到了反射),因此执行的效率非常高。

使用方式:

import "gitee.com/johng/gf/g/util/gconv"

方法列表: godoc.org/github.com/johng-cn/gf/g/util/gconv

// 基本类型
func Bool(i interface{}) bool
func Float32(i interface{}) float32
func Float64(i interface{}) float64
func Int(i interface{}) int
func Int16(i interface{}) int16
func Int32(i interface{}) int32
func Int64(i interface{}) int64
func Int8(i interface{}) int8
func String(i interface{}) string
func Uint(i interface{}) uint
func Uint16(i interface{}) uint16
func Uint32(i interface{}) uint32
func Uint64(i interface{}) uint64
func Uint8(i interface{}) uint8 // slice类型
func Bytes(i interface{}) []byte
func Ints(i interface{}) []int
func Floats(i interface{}) []float64
func Strings(i interface{}) []string
func Interfaces(i interface{}) []interface{} // 时间类型
func Time(i interface{}, format ...string) time.Time
func TimeDuration(i interface{}) time.Duration // 对象转换
func Struct(params interface{}, objPointer interface{}, attrMapping ...map[string]string) error // 根据类型名称执行基本类型转换(非struct转换))
func Convert(i interface{}, t string, extraParams ...interface{}) interface{}

基本使用

常用基本类型的转换方法比较简单,我们这里使用一个例子来演示转换方法的使用及效果。

package main

import (
"fmt"
"gitee.com/johng/gf/g/util/gconv"
) func main() {
i := 123
fmt.Printf("%10s %v\n", "Int:", gconv.Int(i))
fmt.Printf("%10s %v\n", "Int8:", gconv.Int8(i))
fmt.Printf("%10s %v\n", "Int16:", gconv.Int16(i))
fmt.Printf("%10s %v\n", "Int32:", gconv.Int32(i))
fmt.Printf("%10s %v\n", "Int64:", gconv.Int64(i))
fmt.Printf("%10s %v\n", "Uint:", gconv.Uint(i))
fmt.Printf("%10s %v\n", "Uint8:", gconv.Uint8(i))
fmt.Printf("%10s %v\n", "Uint16:", gconv.Uint16(i))
fmt.Printf("%10s %v\n", "Uint32:", gconv.Uint32(i))
fmt.Printf("%10s %v\n", "Uint64:", gconv.Uint64(i))
fmt.Printf("%10s %v\n", "Float32:", gconv.Float32(i))
fmt.Printf("%10s %v\n", "Float64:", gconv.Float64(i))
fmt.Printf("%10s %v\n", "Bool:", gconv.Bool(i))
fmt.Printf("%10s %v\n", "String:", gconv.String(i)) fmt.Printf("%10s %v\n", "Bytes:", gconv.Bytes(i))
fmt.Printf("%10s %v\n", "Strings:", gconv.Strings(i))
fmt.Printf("%10s %v\n", "Ints:", gconv.Ints(i))
fmt.Printf("%10s %v\n", "Floats:", gconv.Floats(i))
fmt.Printf("%10s %v\n", "Interfaces:", gconv.Interfaces(i))
}

执行后,输出结果为:

      Int: 123
Int8: 123
Int16: 123
Int32: 123
Int64: 123
Uint: 123
Uint8: 123
Uint16: 123
Uint32: 123
Uint64: 123
Float32: 123
Float64: 123
Bool: true
String: 123
Bytes: [123]
Strings: [123]
Ints: [123]
Floats: [123]
Interfaces: [123]

Struct转换

项目中我们经常会遇到大量struct的使用,以及各种数据类型到struct的转换/赋值(特别是json/xml/各种协议编码转换的时候)。为提高编码及项目维护效率,gconv模块为各位开发者带来了极大的福利,为数据解析提供了更高的灵活度。

gconv模块执行struct转换的方法仅有一个,定义如下:

func Struct(params interface{}, objPointer interface{}, attrMapping ...map[string]string) error

其中:

  1. params为需要转换到struct的变量参数,可以为任意数据类型,常见的数据类型为map
  2. objPointer为需要执行转的目标struct对象,这个参数必须为该struct的对象指针,转换成功后该对象的属性将会更新;
  3. attrMapping为自定义的map键名strcut属性之间的映射关系,此时params参数必须为map类型,否则该参数无意义;

转换规则

gconv模块的struct转换特性非常强大,支持任意数据类型到struct属性的映射转换。在没有提供自定义attrMapping转换规则的情况下,默认的转换规则如下:

  1. struct中需要匹配的属性必须为公开属性(首字母大小);
  2. 根据params类型的不同,逻辑会有不同:

    • params参数为map: 键名会自动按照 不区分大小写 且 忽略-/_/空格符号 的形式与struct属性进行匹配;
    • params参数为其他类型: 将会把该变量值与struct的第一个属性进行匹配;
    • 此外,如果struct的属性为复杂数据类型如slice,map,strcut那么会进行递归匹配赋值;
  3. 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略;

以下是几个匹配的示例:

map键名    struct属性     是否匹配
name Name match
Email Email match
nickname NickName match
NICKNAME NickName match
Nick-Name NickName match
nick_name NickName match
nick name NickName match
NickName Nick_Name match
Nick-name Nick_Name match
nick_name Nick_Name match
nick name Nick_Name match

示例1,基本使用

package main

import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/util/gconv"
) type User struct {
Uid int
Name string
Site_Url string
NickName string
Pass1 string `gconv:"password1"`
Pass2 string `gconv:"password2"`
} func main() {
user := (*User)(nil) // 使用默认映射规则绑定属性值到对象
user = new(User)
params1 := g.Map{
"uid" : 1,
"Name" : "john",
"siteurl" : "https://gfer.me",
"nick_name" : "johng",
"PASS1" : "123",
"PASS2" : "456",
}
if err := gconv.Struct(params1, user); err == nil {
g.Dump(user)
} // 使用struct tag映射绑定属性值到对象
user = new(User)
params2 := g.Map {
"uid" : 2,
"name" : "smith",
"site-url" : "https://gfer.me",
"nick name" : "johng",
"password1" : "111",
"password2" : "222",
}
if err := gconv.Struct(params2, user); err == nil {
g.Dump(user)
}
}

可以看到,我们可以直接通过Struct方法将map按照默认规则绑定到struct上,也可以使用struct tag的方式进行灵活的设置。此外,Struct方法有第三个map参数,用于指定自定义的参数名称到属性名称的映射关系。

执行后,输出结果为:

{
"Uid": 1,
"Name": "john",
"Site_Url": "https://gfer.me",
"NickName": "johng",
"Pass1": "123",
"Pass2": "456"
}
{
"Uid": 2,
"Name": "smith",
"Site_Url": "https://gfer.me",
"NickName": "johng",
"Pass1": "111",
"Pass2": "222"
}

示例2,复杂类型转换

1. slice基本类型属性

package main

import (
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g"
"fmt"
) // 演示slice类型属性的赋值
func main() {
type User struct {
Scores []int
} user := new(User)
scores := []interface{}{99, 100, 60, 140} // 通过map映射转换
if err := gconv.Struct(g.Map{"Scores" : scores}, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
} // 通过变量映射转换,直接slice赋值
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}

执行后,输出结果为:

{
"Scores": [
99,
100,
60,
140
]
}
{
"Scores": [
99,
100,
60,
140
]
}

2. struct属性为struct

package main

import (
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g"
"fmt"
) func main() {
type Score struct {
Name string
Result int
}
type User struct {
Scores Score
} user := new(User)
scores := map[string]interface{}{
"Scores" : map[string]interface{}{
"Name" : "john",
"Result" : 100,
},
} // 嵌套struct转换
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}

执行后,输出结果为:

{
"Scores": {
"Name": "john",
"Result": 100
}
}

3. struct属性为slice,数值为slice

package main

import (
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g"
"fmt"
) func main() {
type Score struct {
Name string
Result int
}
type User struct {
Scores []Score
} user := new(User)
scores := map[string]interface{}{
"Scores" : []interface{}{
map[string]interface{}{
"Name" : "john",
"Result" : 100,
},
map[string]interface{}{
"Name" : "smith",
"Result" : 60,
},
},
} // 嵌套struct转换,属性为slice类型,数值为slice map类型
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}

执行后,输出结果为:

{
"Scores": [
{
"Name": "john",
"Result": 100
},
{
"Name": "smith",
"Result": 60
}
]
}

4. struct属性为slice,数值为非slice

package main

import (
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g"
"fmt"
) func main() {
type Score struct {
Name string
Result int
}
type User struct {
Scores []Score
} user := new(User)
scores := map[string]interface{}{
"Scores" : map[string]interface{}{
"Name" : "john",
"Result" : 100,
},
} // 嵌套struct转换,属性为slice类型,数值为map类型
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}

执行后,输出结果为:

{
"Scores": [
{
"Name": "john",
"Result": 100
}
]
}

golang类型转换模块之gconv的更多相关文章

  1. mybaits源码分析--类型转换模块(三)

    一.类型转换模块 String sql = "SELECT id,user_name,real_name,password,age,d_id from t_user where id = ? ...

  2. golang 类型断言的学习

    在php中有一个 serialize() 函数 可以把数组序列化成字符串进行存储和传输 如果想反序列化这种字符串,在php中只需要一个简单的unserialize() 函数就可以完成了.但是在gola ...

  3. golang类型断言

    一.介绍 类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用类型断言 例子: package main import "fmt" func main(){ ...

  4. [Go] golang类型断言

    类型断言有点像向下转型,接口类型转到具体的实现实例类型上类型断言是一个使用在接口值上的操作.语法上它看起来像x.(T)被称为断言类型,这里x表示一个接口的类型和T表示一个类型 package main ...

  5. golang类型判断

    _.ok:=interface{}(a).(B) 此语句用于判断对象a是否是B类型 也可以判断对象a是否实现了B接口 package main import "fmt" type ...

  6. Golang 类型定义总结手册| 面试最基础

    变量 var 关键字是 var ,定义后须被调用 支持多个同时定义 支持使用 := 缺省定义 变量定义(声明) //使用var 关键字 进行变量定义 : var + 变量名 + 变量类型 //Var ...

  7. golang类型转化

     int 转 float mean:= float32(sum)   float 转 int a := 5.0 b := int(a)   string 转 int i,_ := strconv.At ...

  8. golang动态加载原生代码思路

    golang动态加载原生代码思路(非plugin,非so文件.使用mmap形式运行机器码,可释放) 1.用go tool objdump,可以看到任意函数的机器码.汇编指令.偏移.(go源码下面有一个 ...

  9. golang martini 源码阅读笔记之inject

    martini是go语言写的一个超级轻量的web开源框架,具体源码可在github搜索找到.13年那会开始接触go语言时有稍微看过这个框架,由于之后没有继续使用go就慢慢忽略了,最近由于手头项目可能会 ...

  10. golang cgo 使用总结

    原文地址 CGO 提供了 golang 和 C 语言相互调用的机制.某些第三方库可能只有 C/C++ 的实现,完全用纯 golang 的实现可能工程浩大,这时候 CGO 就派上用场了.可以通 CGO ...

随机推荐

  1. C#设计模式入门实战教程

    什么是设计模式 设计模式是对面向对象设计中反复出现的问题的解决方案.它们提供了被反复使用.多数人知晓的.经过分类编目的代码设计经验总结. 设计模式的作用 提高代码的可重用性:通过定义一套标准的解决方案 ...

  2. 【YashanDB数据库】YAS-02032 column type is incompatible with referenced column type

    [标题]错误码处理 [问题分类]外键约束创建报错 [关键字]YAS-02032 [问题描述]设置外键约束报错,数据元数据不正确. [问题原因分析]外键字段类型不支持,比如varchar2(64) ,指 ...

  3. python 或者 pyspark 和 java 交互, pyspark 里怎么调用自定义的 jar 包

    1. python 直接访问 jar 里面的类 先定义java文件,然后要访问java class, 需要有gateway server 和 entrypoint, 到时候python就可以连接上ga ...

  4. Tenzing and Random Operations CF1842G 题解

    [1] 分析 设 \(m\) 次选的位置分别为 \(b_{1\sim m}\). 于是答案为 \(\mathbb E(\prod\limits_{i = 1}^{n}(a_i + \sum\limit ...

  5. Mybatis骚操作-通用查询工具类

    老项目大多都有对JDBC进行了封装,可以直接执行SQL的工具类,在做项目升级改造的时候(这里仅指整合mybatis),要么全部调整成dao-xml的形式(会有改动代码多的问题,而且看代码时需要xml和 ...

  6. 合合信息亮相“海聚英才”全球创新创业峰会,政企研合力推动AI人才培养

    近日,"聚上海,创未来"第三届"海聚英才"全球创新创业峰会在沪举行,"创新之路:卓越工程师培养交流研讨会"(简称"研讨会" ...

  7. 使用Navicat Premium 将数据库导入、导出方法

    数据库导出 1.双击要导出的数据库,右键选转储SQL文件-,选择要保存的文件夹. 2.点击开始后,开始导出. 数据库导入 1.新建数据库,数据库的名字必须和导入的数据库文件一致. 2.在新建的数据库右 ...

  8. Navicat Premium 12的下载和安装

    首先下载navicate程序以及破解文件,这里一并存到了百度网盘直接下载即可 链接:https://pan.baidu.com/s/1a2QKHHUZ0ej1D78CjQ1ldA提取码:klus 解压 ...

  9. Linux下挂载SD卡,以及容易犯的误区

    1.插入SD卡 如果系统能够识别SD卡,则会打印一些信息: 2.查看系统给SD卡分配的设备名 命令如下: fdisk -l 说明:通常是根据SD卡的存储容量来确定的. 比如下面的信息: 3.挂载SD卡 ...

  10. manim边学边做--形状匹配

    manim中有几个特殊的用于形状匹配的对象,它们的作用是标记和注释已有的对象,本身一般不单独使用. 形状匹配对象一共有4种: BackgroundRectangle:为已有的对象提供一个矩形的背景 C ...