Golang類型轉換模塊 - gconv

原文地址:https://gfer.me/util/gconv/indexhtml

gf框架提供了很是強大的類型轉換包gconv,能夠實現將任何數據類型轉換爲指定的數據類型,對經常使用基本數據類型之間的無縫轉換,同時也支持任意類型到struct對象的屬性賦值。因爲gconv模塊內部大量使用了斷言而非反射(僅struct轉換使用到了反射),所以執行的效率很是高。linux

使用方式:git

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

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

// 基本類型
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{}

基本使用

經常使用基本類型的轉換方法比較簡單,咱們這裏使用一個例子來演示轉換方法的使用及效果。shell

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))
}

執行後,輸出結果爲:json

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模塊爲各位開發者帶來了極大的福利,爲數據解析提供了更高的靈活度。app

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
        }
    ]
}

基準性能測試

測試轉換變量值爲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
相關文章
相關標籤/搜索