英文:
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: ¬ify_id,
NotifyTime: ¬ify_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(¬ifyLog)
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 < 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(""))
Use it like this:
var model ALiNotifyLog
setStringpFields(&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 &s
}
return nil
}
Use that function to initialize the fields:
model := payment.ALiNotifyLog{
APPId: stringp("app_id"),
AuthAppId: stringp("auth_app_id"),
...
TradeStatus: stringp("trade_status")}
res := global.Orm.Table(paynotifylog).Create(&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 < 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()
答案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 (
"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)
}
Output:
> &map[This:42 thaaaaat:foobar]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论