我有一个存储JSON的数据库,还有一个提供外部API的服务器,通过HTTP post,可以更改数据库中的值.数据库在内部由不同的进程使用,因此有一个通用的命名方案.

客户看到的密钥不同,但是将数据库中的密钥映射为1:1(有未公开的密钥).例如:

这是在数据库中:

{ "bit_size": 8, "secret_key": false }

这将呈现给客户端:

{ "num_bits": 8 }

API可以根据字段名称进行更改,但数据库始终具有一致的键.

我在 struct 中对字段进行了相同的命名,但对json编码器使用了不同的标志:

type DB struct {
    NumBits int  `json:"bit_size"`
    Secret  bool `json:"secret_key"`
}
type User struct {
    NumBits int `json:"num_bits"`
}

我用encoding/json来做封送/解封.

reflect是用来做这件事的合适工具吗?所有的 keys 都是一样的,有没有更简单的方法?我考虑的是某种memcpy(如果我保持用户字段的顺序不变).

推荐答案

下面是一个使用反射的解决方案.如果你需要更复杂的 struct 和嵌入的 struct 域等等,你必须进一步开发它.

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
}

Go相关问答推荐

在连接表中以添加字段作为主要关键字的多对多

Go GORM创建表,但不创建列

Golang Viper:如果第一个字段不存在,如何从另一个字段获取值

Golang中的泛型 struct /接口列表

如何解析Go-Gin多部分请求中的 struct 切片

Go 是否提供了标准或事实上的方法来处理单个语句中的错误(即内联错误处理)?

将这两个函数合二为一的惯用方法

Golang Gorm Fiber - 如何将定义为别名的名称发送到索引模板?

我应该先解锁然后再广播吗?

golang / urfave.cli:无法手动设置标志

AWS Lambda 中的 Websocket URL 超时达到错误

你如何在 Golang 代码中测试 filepath.Abs​​ 失败?

泛型:实现嵌套接口

Gorm 预加载给出了模糊的列错误

emersion/go-imap - imap.FetchRFC822:无效内存地址或零指针取消引用

Go AST:获取所有 struct

如何使用golang操作很长的字符串以避免内存不足

什么是无效字符实体 &ccb

正确编码 JWT

如何在 docker 文件中安装 golang 包?