golang根據結構體A轉化為結構體B的方法
阿新 • • 發佈:2018-12-17
業務場景:
在使用go-xorm框架,mysql資料庫,json格式傳參的時候,一種情況:資料庫的欄位非varchar型別,且該欄位可空.
此時如果我們定義接收前端引數的結構體對應該欄位為string時, 前端傳入的值為空時,我們後臺unmarshal之後,該欄位對應的值為空;例如: 後臺資料庫有一個欄位total_fee是float 型別, 此時如果要往插入該條資料,我們可以採用兩種方法:
1.拼接sql, 此時我們需要判斷total_fee是否為空,因為,如果往資料插入""的時候,因為資料對應的float型別,會報錯,所以直接不拼接這個欄位是可以解決的.
2.將前端傳入的引數轉化,和資料庫對應起來.
因為拼接sql工程量大,且容易出錯,所以我們這裡介紹第二種方法,然後直接利用go-xorm的insert()方法插入資料.
解決程式碼:
package main import ( "reflect" "github.com/mitchellh/mapstructure" "fmt" "time" "strings" ) type A struct { Name string Id int TheTime string Price string } type B struct { Name string Id string TheTime interface{} Price interface{} } //定義一個方法,將結構體A轉化為B func StructAtoB (a interface{},b interface{}) map[string]interface{}{ //第一步,先將結構體轉化為map方便後續遍歷 amap := Struct2Map(a) bmap := Struct2Map(b) //開始遍歷A結構體的欄位 for k1, v1 := range amap { for k2,v2:= range bmap { typea := reflect.TypeOf(v1) typeb := reflect.TypeOf(v2) if k1 == k2 && typea==typeb { bmap[k2] = v1 } if k1==k2 && typea!=typeb { //如果要轉換的是number型別 if typeb == tInterface { fmt.Println("要轉換的是字串型別") //因為我們公司時間型別開放給前端的型別是字串,所以我們直接用string轉換為datetime //1.斷言v1為string vs, ok := v1.(string) if ok { fmt.Println("開始轉換number") if vs == "" { //v2 = nil //bmap[k2]=v2 continue } bmap[k2] = v1 } } } } } return bmap } func Struct2Map(obj interface{}) map[string]interface{} { t := reflect.TypeOf(obj) v := reflect.ValueOf(obj) var data = make(map[string]interface{}) for i := 0; i < t.NumField(); i++ { data[t.Field(i).Name] = v.Field(i).Interface() } return data } func main() { var a A var b B a.Name="namea" a.Id = 2 a.TheTime ="20180304" a.Price = "1.0" mapre := StructAtoB(a,b) if err := mapstructure.Decode(mapre, &b); err != nil { fmt.Println("the err when unmarshal mapstructure is:",err) } fmt.Println("the result is :",b) fmt.Printf("the b'prcie is :%v,and b's type is:%T",b.Price,b.Price) }
侷限性:目前只解決了前端傳入為string的情況, 入參不能為指標型別,只能是普通的結構體.