我有一个存储JSON的数据库,以及一个提供外部API的服务器,通过它可以通过HTTP发布更改此数据库中的值。数据库由内部的不同进程使用,因此具有通用的命名方案。
客户看到的密钥不同,但是将1:1与数据库中的密钥映射(有未公开的密钥)。例如:
这是在数据库中:
{ "bit_size": 8, "secret_key": false }
这是呈现给客户的:
{ "num_bits": 8 }
API可以根据字段名称进行更改,但是数据库始终具有一致的密钥。
我已经在结构中将字段命名为相同,但对json编码器使用了不同的标志:
type DB struct { NumBits int `json:"bit_size"` Secret bool `json:"secret_key"` } type User struct { NumBits int `json:"num_bits"` }
我encoding/json过去经常做元帅/元帅。
encoding/json
是reflect正确的工具吗?因为所有键都相同,有没有更简单的方法?我在想某种memcpy(如果我将用户字段的顺序保持一致)。
reflect
memcpy
这是使用反射的解决方案。如果您需要带有嵌入式结构字段等的更复杂的结构,则必须进一步开发它。
http://play.golang.org/p/iTaDgsdSaI
package main import ( "encoding/json" "fmt" "reflect" ) type M map[string]interface{} // just an alias var Record = []byte(`{ "bit_size": 8, "secret_key": false }`) type DB struct { NumBits int `json:"bit_size"` Secret bool `json:"secret_key"` } type User struct { NumBits int `json:"num_bits"` } func main() { d := new(DB) e := json.Unmarshal(Record, d) if e != nil { panic(e) } m := mapFields(d) fmt.Println("Mapped fields: ", m) u := new(User) o := applyMap(u, m) fmt.Println("Applied map: ", o) j, e := json.Marshal(o) if e != nil { panic(e) } fmt.Println("Output JSON: ", string(j)) } func applyMap(u *User, m M) M { t := reflect.TypeOf(u).Elem() o := make(M) for i := 0; i < t.NumField(); i++ { f := t.FieldByIndex([]int{i}) // skip unexported fields if f.PkgPath != "" { continue } if x, ok := m[f.Name]; ok { k := f.Tag.Get("json") o[k] = x } } return o } func mapFields(x *DB) M { o := make(M) v := reflect.ValueOf(x).Elem() t := v.Type() for i := 0; i < v.NumField(); i++ { f := t.FieldByIndex([]int{i}) // skip unexported fields if f.PkgPath != "" { continue } o[f.Name] = v.FieldByIndex([]int{i}).Interface() } return o }