GoFrame 類型轉(zhuǎn)換-Struct轉(zhuǎn)換

2022-03-30 15:44 更新

項目中我們經(jīng)常會遇到大量?struct?的使用,以及各種數(shù)據(jù)類型到?struct?的轉(zhuǎn)換/賦值(特別是?json/xml?/各種協(xié)議編碼轉(zhuǎn)換)。為提高編碼及項目維護效率,?gconv?模塊為各位開發(fā)者帶來了極大的福利,為數(shù)據(jù)解析提供了更高的靈活度。

?gconv?模塊通過?Struct?轉(zhuǎn)換方法執(zhí)行?struct?類型轉(zhuǎn)換,其定義如下:

// Struct maps the params key-value pairs to the corresponding struct object's attributes.
// The third parameter `mapping` is unnecessary, indicating the mapping rules between the
// custom key name and the attribute name(case sensitive).
//
// Note:
// 1. The `params` can be any type of map/struct, usually a map.
// 2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object
//    or struct pointer.
// 3. Only the public attributes of struct object can be mapped.
// 4. If `params` is a map, the key of the map `params` can be lowercase.
//    It will automatically convert the first letter of the key to uppercase
//    in mapping procedure to do the matching.
//    It ignores the map key, if it does not match.
func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error)

其中:

  1. ?params?為需要轉(zhuǎn)換到?struct?的變量參數(shù),可以為任意數(shù)據(jù)類型,常見的數(shù)據(jù)類型為?map?。
  2. ?pointer?為需要執(zhí)行轉(zhuǎn)的目標(biāo)?struct?對象,這個參數(shù)必須為該?struct?的對象指針,轉(zhuǎn)換成功后該對象的屬性將會更新。
  3. ?mapping?為自定義的?map?鍵名到?strcut?屬性之間的映射關(guān)系,此時?params?參數(shù)必須為?map?類型,否則該參數(shù)無意義。大部分場景下使用可以不用提供該參數(shù),直接使用默認(rèn)的轉(zhuǎn)換規(guī)則即可。

更多的?struct?相關(guān)轉(zhuǎn)換方法請參考接口文檔:https://pkg.go.dev/github.com/gogf/gf/v2/util/gconv

轉(zhuǎn)換規(guī)則

?gconv?模塊的?struct?轉(zhuǎn)換特性非常強大,支持任意數(shù)據(jù)類型到?struct?屬性的映射轉(zhuǎn)換。在沒有提供自定義?mapping?轉(zhuǎn)換規(guī)則的情況下,默認(rèn)的轉(zhuǎn)換規(guī)則如下:

  1. ?struct?中需要匹配的屬性必須為 公開屬性 (首字母大寫)。
  2. 根據(jù)?params?類型的不同,邏輯會有不同:
    • ?params?參數(shù)類型為?map?:鍵名會自動按照 不區(qū)分大小寫 且 忽略特殊字符 的形式與?struct?屬性進行匹配。
    • ?params?參數(shù)為其他類型:將會把該變量值與?struct?的第一個屬性進行匹配。
    •  此外,如果?struct?的屬性為復(fù)雜數(shù)據(jù)類型如?slice?,?map?,?strcut?那么會進行遞歸匹配賦值。
  3. 如果匹配成功,那么將鍵值賦值給屬性,如果無法匹配,那么忽略該鍵值。

以下是幾個?map?鍵名與?struct?屬性名稱的示例:

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

自動創(chuàng)建對象

當(dāng)給定的?pointer?參數(shù)類型為?**struct?時,?Struct?方法內(nèi)部將會自動創(chuàng)建該?struct?對象,并修改傳遞變量指向的指針地址。

package main

import (
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

func main() {
	type User struct {
		Uid  int
		Name string
	}
	params := g.Map{
		"uid":  1,
		"name": "john",
	}
	var user *User
	if err := gconv.Struct(params, &user); err != nil {
		panic(err)
	}
	g.Dump(user)
}

執(zhí)行后,輸出結(jié)果為:

{
	"Name": "john",
	"Uid": 1
}

Struct遞歸轉(zhuǎn)換

遞歸轉(zhuǎn)換是指當(dāng)?struct?對象包含子對象時,并且子對象是?embedded?方式定義時,可以將?params?參數(shù)數(shù)據(jù)(第一個參數(shù))同時遞歸地映射到其子對象上,常用于帶有繼承對象的?struct?上。

package main

import (
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

func main() {
	type Ids struct {
		Id         int    `json:"id"`
		Uid        int    `json:"uid"`
	}
	type Base struct {
		Ids
		CreateTime string `json:"create_time"`
	}
	type User struct {
		Base
		Passport   string `json:"passport"`
		Password   string `json:"password"`
		Nickname   string `json:"nickname"`
	}
	data := g.Map{
		"id"          : 1,
		"uid"         : 100,
		"passport"    : "john",
		"password"    : "123456",
		"nickname"    : "John",
		"create_time" : "2019",
	}
	user := new(User)
	gconv.Struct(data, user)
	g.Dump(user)
}

執(zhí)行后,終端輸出結(jié)果為:

{
	"Base": {
		"id": 1,
		"uid": 100,
		"create_time": "2019"
	},
	"nickname": "John",
	"passport": "john",
	"password": "123456"
}

示例1,基本使用

package main

import (
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

type User struct {
	Uid      int
	Name     string
	SiteUrl  string
	NickName string
	Pass1    string `c:"password1"`
	Pass2    string `c:"password2"`
}

func main() {
	var user *User

	// 使用默認(rèn)映射規(guī)則綁定屬性值到對象
	user = new(User)
	params1 := g.Map{
		"uid":       1,
		"Name":      "john",
		"site_url":  "https://goframe.org",
		"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://goframe.org",
		"nick name": "johng",
		"password1": "111",
		"password2": "222",
	}
	if err := gconv.Struct(params2, user); err == nil {
		g.Dump(user)
	}
}

可以看到,我們可以直接通過?Struct?方法將?map?按照默認(rèn)規(guī)則綁定到?struct?上,也可以使用?struct tag?的方式進行靈活的設(shè)置。此外,?Struct?方法有第三個?map?參數(shù),用于指定自定義的參數(shù)名稱到屬性名稱的映射關(guān)系。

執(zhí)行后,輸出結(jié)果為:

{
    "Uid": 1,
    "Name": "john",
    "SiteUrl": "https://goframe.org",
    "NickName": "johng",
    "Pass1": "123",
    "Pass2": "456"
}

{
    "Uid": 2,
    "Name": "smith",
    "SiteUrl": "https://goframe.org",
    "NickName": "johng",
    "Pass1": "111",
    "Pass2": "222"
}

示例2,復(fù)雜屬性類型

屬性支持?struct?對象或者?struct?對象指針(目標(biāo)為指針且未?nil?時,轉(zhuǎn)換時會自動初始化)轉(zhuǎn)換。

package main

import (
    "github.com/gogf/gf/v2/util/gconv"
    "github.com/gogf/gf/v2/frame/g"
    "fmt"
)

func main() {
    type Score struct {
        Name   string
        Result int
    }
    type User1 struct {
        Scores Score
    }
    type User2 struct {
        Scores *Score
    }

    user1  := new(User1)
    user2  := new(User2)
	scores := g.Map{
		"Scores": g.Map{
			"Name":   "john",
			"Result": 100,
		},
	}

    if err := gconv.Struct(scores, user1); err != nil {
        fmt.Println(err)
    } else {
        g.Dump(user1)
    }
    if err := gconv.Struct(scores, user2); err != nil {
        fmt.Println(err)
    } else {
        g.Dump(user2)
    }
}

執(zhí)行后,輸出結(jié)果為:

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


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號