分享
  1. 首页
  2. 文章

Golang类型转换模块 - gconv

John · · 1797 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

文章来源:https://gfer.me/util/gconv/index

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 not match
nick_name NickName not match
nick_name Nick_Name match

示例1,基本使用

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

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

执行后,输出结果为:

&{1 john 123 456}
&{2 smith 111 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
 }
 ]
}

基准性能测试

测试转换变量值为123456789,类型int

john@john-B85M:~/Workspace/Go/GOPATH/src/gitee.com/johng/gf/g/util/gconv$ go test *.go -bench=".*" -benchmem
goos: linux
goarch: amd64
BenchmarkString-4 20000000 71.8 ns/op 24 B/op 2 allocs/op
BenchmarkInt-4 100000000 22.2 ns/op 8 B/op 1 allocs/op
BenchmarkInt8-4 100000000 24.5 ns/op 8 B/op 1 allocs/op
BenchmarkInt16-4 50000000 23.8 ns/op 8 B/op 1 allocs/op
BenchmarkInt32-4 100000000 24.1 ns/op 8 B/op 1 allocs/op
BenchmarkInt64-4 100000000 21.7 ns/op 8 B/op 1 allocs/op
BenchmarkUint-4 100000000 22.2 ns/op 8 B/op 1 allocs/op
BenchmarkUint8-4 50000000 25.6 ns/op 8 B/op 1 allocs/op
BenchmarkUint16-4 50000000 32.1 ns/op 8 B/op 1 allocs/op
BenchmarkUint32-4 50000000 27.7 ns/op 8 B/op 1 allocs/op
BenchmarkUint64-4 50000000 28.1 ns/op 8 B/op 1 allocs/op
BenchmarkFloat32-4 10000000 155 ns/op 24 B/op 2 allocs/op
BenchmarkFloat64-4 10000000 177 ns/op 24 B/op 2 allocs/op
BenchmarkTime-4 5000000 240 ns/op 72 B/op 4 allocs/op
BenchmarkTimeDuration-4 50000000 26.2 ns/op 8 B/op 1 allocs/op
BenchmarkBytes-4 10000000 149 ns/op 128 B/op 3 allocs/op
BenchmarkStrings-4 10000000 223 ns/op 40 B/op 3 allocs/op
BenchmarkInts-4 20000000 55.0 ns/op 16 B/op 2 allocs/op
BenchmarkFloats-4 10000000 186 ns/op 32 B/op 3 allocs/op
BenchmarkInterfaces-4 20000000 66.6 ns/op 24 B/op 2 allocs/op
PASS
ok command-line-arguments 35.356s

有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:John

查看原文:Golang类型转换模块 - gconv

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1797 次点击
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏