原文地址: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的轉換/賦值(特別是json
/xml
/各類協議編碼轉換的時候)。爲提升編碼及項目維護效率,gconv
模塊爲各位開發者帶來了極大的福利,爲數據解析提供了更高的靈活度。app
gconv
模塊執行struct
轉換的方法僅有一個,定義以下:框架
func Struct(params interface{}, objPointer interface{}, attrMapping ...map[string]string) error
其中:性能
params
爲須要轉換到struct
的變量參數,能夠爲任意數據類型,常見的數據類型爲map
;objPointer
爲須要執行轉的目標struct
對象,這個參數必須爲該struct
的對象指針,轉換成功後該對象的屬性將會更新;attrMapping
爲自定義的map鍵名
到strcut屬性
之間的映射關係,此時params
參數必須爲map類型,不然該參數無心義;gconv
模塊的struct
轉換特性很是強大,支持任意數據類型到struct
屬性的映射轉換。在沒有提供自定義attrMapping
轉換規則的狀況下,默認的轉換規則以下:測試
struct
中須要匹配的屬性必須爲公開屬性
(首字母大小);根據params
類型的不一樣,邏輯會有不一樣:
params
參數爲map
: 鍵名會自動按照 不區分大小寫
且 忽略-/_/空格
符號 的形式與struct
屬性進行匹配;params
參數爲其餘類型: 將會把該變量值與struct
的第一個屬性進行匹配;struct
的屬性爲複雜數據類型如slice
,map
,strcut
那麼會進行遞歸匹配賦值;如下是幾個匹配的示例:
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
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" }
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 ] }
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 } }
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 } ] }
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