Is there an easy way to create a struct in golang?

huangapple go评论111阅读模式
英文:

Is there an easy way to create a struct in golang?

问题

我有一个结构体,现在想要从接收到的HTTP数据实例化它。但是我写的代码现在很繁琐,有很多行代码。有没有办法简化代码?除了id字段之外,所有字段都可以对应。

模型

type ALiNotifyLog struct {
	ID             *int    `json:"id"`
	APPId          *string `json:"app_id"`
	AuthAppId      *string `json:"auth_app_id"`
	BuyerId        *string `json:"buyer_id"`
	BuyerPayAmount *string `json:"buyer_pay_amount"`
	GmtCreate      *string `json:"gmt_create"`
	GmtPayment     *string `json:"gmt_payment"`
	InvoiceAmount  *string `json:"invoice_amount"`
	NotifyId       *string `json:"notify_id"`
	NotifyTime     *string `json:"notify_time"`
	OutTradeNo     *string `json:"out_trade_no"`
	PointAmount    *string `json:"point_amount"`
	ReceiptAmount  *string `json:"receipt_amount"`
	Sign           *string `json:"sign"`
	TotalAmount    *string `json:"total_amount"`
	TradeNo        *string `json:"trade_no"`
	TradeStatus    *string `json:"trade_status"`
}

函数

func SaveData(data map[string]interface{}) {
	app_id := data["app_id"].(string)
	auth_app_id := data["auth_app_id"].(string)
	buyer_id := data["buyer_id"].(string)
	buyer_pay_amount := data["buyer_pay_amount"].(string)
	gmt_create := data["gmt_create"].(string)
	gmt_payment := data["gmt_payment"].(string)
	invoice_amount := data["invoice_amount"].(string)
	notify_id := data["notify_id"].(string)
	notify_time := data["notify_time"].(string)
	out_trade_no := data["out_trade_no"].(string)
	point_amount := data["point_amount"].(string)
	receipt_amount := data["receipt_amount"].(string)
	sign := data["sign"].(string)
	total_amount := data["total_amount"].(string)
	trade_no := data["trade_no"].(string)
	trade_status := data["trade_status"].(string)
	
	model := payment.ALiNotifyLog{
		APPId:          &app_id,
		AuthAppId:      &auth_app_id,
		BuyerId:        &buyer_id,
		BuyerPayAmount: &buyer_pay_amount,
		GmtCreate:      &gmt_create,
		GmtPayment:     &gmt_payment,
		InvoiceAmount:  &invoice_amount,
		NotifyId:       &notify_id,
		NotifyTime:     &notify_time,
		OutTradeNo:     &out_trade_no,
		PointAmount:    &point_amount,
		ReceiptAmount:  &receipt_amount,
		Sign:           &sign,
		TotalAmount:    &total_amount,
		TradeNo:        &trade_no,
		TradeStatus:    &trade_status,
	}
	res := global.Orm.Table(paynotifylog).Create(&model)
	fmt.Println(res)
}
英文:

I have a struct and now want to instantiate it from received http data. But now the code I write is cumbersome and has a lot of lines of code. Is there any way to simplify the code? All fields except the field id can correspond

model

type ALiNotifyLog struct {
	ID             *int    `json:"id"`
	APPId          *string `json:"app_id"`
	AuthAppId      *string `json:"auth_app_id"`
	BuyerId        *string `json:"buyer_id"`
	BuyerPayAmount *string `json:"buyer_pay_amount"`
	GmtCreate      *string `json:"gmt_create"`
	GmtPayment     *string `json:"gmt_payment"`
	InvoiceAmount  *string `json:"invoice_amount"`
	NotifyId       *string `json:"notify_id"`
	NotifyTime     *string `json:"notify_time"`
	OutTradeNo     *string `json:"out_trade_no"`
	PointAmount    *string `json:"point_amount"`
	ReceiptAmount  *string `json:"receipt_amount"`
	Sign           *string `json:"sign"`
	TotalAmount    *string `json:"total_amount"`
	TradeNo        *string `json:"trade_no"`
	TradeStatus    *string `json:"trade_status"`
}

func

func SaveData(data map[string]interface{}) {
	app_id := data["app_id"].(string)
	auth_app_id := data["auth_app_id"].(string)
	buyer_id := data["buyer_id"].(string)
	buyer_pay_amount := data["buyer_pay_amount"].(string)
	gmt_create := data["gmt_create"].(string)
	gmt_payment := data["gmt_payment"].(string)
	invoice_amount := data["invoice_amount"].(string)
	notify_id := data["notify_id"].(string)
	notify_time := data["notify_time"].(string)
	out_trade_no := data["out_trade_no"].(string)
	point_amount := data["point_amount"].(string)
	receipt_amount := data["receipt_amount"].(string)
	sign := data["sign"].(string)
	total_amount := data["total_amount"].(string)
	trade_no := data["trade_no"].(string)
	trade_status := data["trade_status"].(string)
	
	model := payment.ALiNotifyLog{
		APPId:          &app_id,
		AuthAppId:      &auth_app_id,
		BuyerId:        &buyer_id,
		BuyerPayAmount: &buyer_pay_amount,
		GmtCreate:      &gmt_create,
		GmtPayment:     &gmt_payment,
		InvoiceAmount:  &invoice_amount,
		NotifyId:       &notify_id,
		NotifyTime:     &notify_time,
		OutTradeNo:     &out_trade_no,
		PointAmount:    &point_amount,
		ReceiptAmount:  &receipt_amount,
		Sign:           &sign,
		TotalAmount:    &total_amount,
		TradeNo:        &trade_no,
		TradeStatus:    &trade_status}
	res := global.Orm.Table(paynotifylog).Create(&model)
	fmt.Println(res)
}

答案1

得分: 2

我看到你有一个JSON对象,你想直接将其解码为一个结构体实例。

你可以按照以下代码片段的结构来编写代码:

type ALiNotifyLog struct {
	// 在这里定义你的字段
}

func parseRequest(r *http.Request) {
	var notifyLog ALiNotifyLog
	err := json.NewDecoder(r.Body).Decode(&notifyLog)
	if err != nil {
		// 处理错误
	}

	// ............ 更多代码

}

func SaveData(data ALiNotifyLog) {
	res := global.Orm.Table(paynotifylog).Create(&data)
	fmt.Println(res)

	// ........... 更多代码
}

希望这可以帮助到你!

英文:

I see that you are JSON. May be decode the JSON directly into a struct instance.

I will structure the code something like the below snippet:

type ALiNotifyLog struct {
// your fields here
}
func parseRequest(r *http.Request) {
var notifyLog ALiNotifyLog
err := json.NewDecoder(r.Body).Decode(&notifyLog)
if err != nil {
// do something
}
// ............ more code
}
func SaveData(data ALiNotifyLog) {
res := global.Orm.Table(paynotifylog).Create(&data)
fmt.Println(res)
// ........... more code
}

答案2

得分: 0

使用reflect包来以编程方式迭代字段:

func setStringpFields(pmodel interface{}, data map[string]interface{}) {
    v := reflect.ValueOf(pmodel).Elem()
    t := v.Type()
    for i := 0; i < t.NumField(); i++ {
        sf := t.Field(i)
        if sf.Type != stringpType {
            continue
        }
        name, _, _ := strings.Cut(sf.Tag.Get("json"), ",")
        if s, ok := data[name].(string); ok {
            v.Field(i).Set(reflect.ValueOf(&s))
        }
    }
}

var stringpType = reflect.PtrTo(reflect.TypeOf(""))

像这样使用它:

var model ALiNotifyLog
setStringpFields(&model, data)

在Go Playground上运行示例:https://go.dev/play/p/IA2-qSOalfg

我省略了在data中缺失的字段。问题中的代码在缺失值时会引发恐慌。

一个更简单的方法是创建一个具有重复功能的函数:

func stringp(data map[string]interface{}, name string) *string {
    if s, ok := data[name].(string); ok {
        return &s
    }
    return nil
}

使用该函数初始化字段:

model := payment.ALiNotifyLog{
    APPId:          stringp(data, "app_id"),
    AuthAppId:      stringp(data, "auth_app_id"),
    ...
    TradeStatus:    stringp(data, "trade_status"),
}
res := global.Orm.Table(paynotifylog).Create(&model)
fmt.Println(res)
英文:

Use the reflect package to programmatically iterate over the fields:

func setStringpFields(pmodel any, data map[string]any) {
v := reflect.ValueOf(pmodel).Elem()
t := v.Type()
for i := 0; i &lt; t.NumField(); i++ {
sf := t.Field(i)
if sf.Type != stringpType {
continue
}
name, _, _ := strings.Cut(sf.Tag.Get(&quot;json&quot;), &quot;,&quot;)
if s, ok := data[name].(string); ok {
v.Field(i).Set(reflect.ValueOf(&amp;s))
}
}
}
var stringpType = reflect.PtrTo(reflect.TypeOf(&quot;&quot;))

Use it like this:

var model ALiNotifyLog
setStringpFields(&amp;model, data)

Run an example on the Go Playground.

I took the liberty of skipping fields that are missing from data. The code in the question panics on a missing value.

A simpler approach is to create a function with the repeated functionality:

func stringp(data map[string]interface{}, name string) *string {
if s, ok := data[name].(string); ok {
return &amp;s
}
return nil
}

Use that function to initialize the fields:

model := payment.ALiNotifyLog{
APPId:          stringp(&quot;app_id&quot;),
AuthAppId:      stringp(&quot;auth_app_id&quot;),
...
TradeStatus:    stringp(&quot;trade_status&quot;)}
res := global.Orm.Table(paynotifylog).Create(&amp;model)
fmt.Println(res)

答案3

得分: 0

1: ScanMapToStruct

func scanMapToStruct(dest interface{}, vals map[string]interface{}) error {
srcValue := indirect(reflect.ValueOf(dest))
srcType := indirectType(reflect.TypeOf(dest))
for m := 0; m < srcType.NumField(); m++ {
field := srcType.Field(m)
fieldName, _ := getFieldName(field)
jsonTypeName := getJsonDataType(field.Type)
if jsonTypeName == "" {
continue
}
v, ok := vals[fieldName].(string)
if !ok {
continue
}
dec := decoders[field.Type.Kind()]
if dec == nil {
continue
}
err := dec(srcValue.Field(m), v)
if err != nil {
fmt.Printf("set field(%s)=%s err:%v\n", fieldName, v, err)
continue
}
}
return nil
}

2: copier.Copy()

英文:

1: ScanMapToStruct

func scanMapToStruct(dest interface{}, vals map[string]interface{}) error {
srcValue := indirect(reflect.ValueOf(dest))
srcType := indirectType(reflect.TypeOf(dest))
for m := 0; m &lt; srcType.NumField(); m++ {
field := srcType.Field(m)
fieldName, _ := getFieldName(field)
jsonTypeName := getJsonDataType(field.Type)
if jsonTypeName == &quot;&quot; {
continue
}
v, ok := vals[fieldName].(string)
if !ok {
continue
}
dec := decoders[field.Type.Kind()]
if dec == nil {
continue
}
err := dec(srcValue.Field(m), v)
if err != nil {
fmt.Printf(&quot;set field(%s)=%s err:%v\n&quot;, fieldName, v, err)
continue
}
}
return nil
}

2: copier.Copy()

答案4

得分: 0

使用GitHub上的mapstructure包。

go get https://github.com/mitchellh/mapstructure
package main

import (
	"log"
	"os"

	"github.com/mitchellh/mapstructure"
)

type MyStruct struct {
	This int
	That string `json:"thaaaaat"`
}

func main() {
	var result map[string]interface{}
	cfg := &mapstructure.DecoderConfig{
		TagName: "json",
		Result:  &result,
	}
	decoder, err := mapstructure.NewDecoder(cfg)
	if err != nil {
		log.Printf("Could not create decoder: %v", err)
		os.Exit(1)
	}
	myData := &MyStruct{
		This: 42,
		That: "foobar",
	}
	err = decoder.Decode(myData)
	if err != nil {
		log.Printf("Decoding failed: %v", err)
		os.Exit(1)
	}
	log.Print(cfg.Result)
}

输出:

&map[This:42 thaaaaat:foobar]

https://go.dev/play/p/mPK_9fEevyC

英文:

Use package mapstructure from GitHub.

go get https://github.com/mitchellh/mapstructure
package main

import (
	&quot;log&quot;
	&quot;os&quot;

	&quot;github.com/mitchellh/mapstructure&quot;
)

type MyStruct struct {
	This int
	That string `json:&quot;thaaaaat&quot;`
}

func main() {
	var result map[string]interface{}
	cfg := &amp;mapstructure.DecoderConfig{
		TagName: &quot;json&quot;,
		Result:  &amp;result,
	}
	decoder, err := mapstructure.NewDecoder(cfg)
	if err != nil {
		log.Printf(&quot;Could not create decoder: %v&quot;, err)
		os.Exit(1)
	}
	myData := &amp;MyStruct{
		This: 42,
		That: &quot;foobar&quot;,
	}
	err = decoder.Decode(myData)
	if err != nil {
		log.Printf(&quot;Decoding failed: %v&quot;, err)
		os.Exit(1)
	}
	log.Print(cfg.Result)
}

Output:

> &map[This:42 thaaaaat:foobar]

https://go.dev/play/p/mPK_9fEevyC

huangapple
  • 本文由 发表于 2022年6月21日 12:09:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/72695240.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定