arrays - Golang,将嵌入式结构转换为数组

标签 arrays json struct go

有没有办法在 Golang 中将结构转换为值数组?

例如,如果我有这种结构(不只是这个):

type Model struct {
    Id        bson.ObjectId   `bson:"_id,omitempty"`
    CreatedAt time.Time       `bson:",omitempty"`
    UpdatedAt time.Time       `bson:",omitempty"`
    DeletedAt time.Time       `bson:",omitempty"`
    CreatedBy bson.ObjectId   `bson:",omitempty"`
    UpdatedBy bson.ObjectId   `bson:",omitempty"`
    DeletedBy bson.ObjectId   `bson:",omitempty"`
    Logs      []bson.ObjectId `bson:",omitempty"`
}

type User struct {
    Name  string `bson:"name"`
    Model `bson:",inline"`
}

情况是,我通常以这种格式将 JSON 发送到浏览器:

var iota = -1
var data = {
  NAME: ++iota, ID: ++iota, CREATED_AT: ++iota, UPDATED_AT: ++iota, DELETED_AT: ++iota, // and so on
  rows: [['kiz',1,'2014-01-01','2014-01-01','2014-01-01'],
         ['yui',2,'2014-01-01','2014-01-01','2014-01-01'],
         ['ham',3,'2014-01-01','2014-01-01','2014-01-01'] // and so on
        ]
};

代替:

var data = {
  rows: [{NAME:'kiz',ID:1,CreatedAt:'2014-01-01',UpdatedAt:'2014-01-01',DeletedAt:'2014-01-01'},
         {NAME:'yui',ID:2,CreatedAt:'2014-01-01',UpdatedAt:'2014-01-01',DeletedAt:'2014-01-01'},
         {NAME:'ham',ID:3,CreatedAt:'2014-01-01',UpdatedAt:'2014-01-01',DeletedAt:'2014-01-01'} // and so on
        ]
}

这是我尝试过的:

import (
    "github.com/kr/pretty"
    //"gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "reflect"
    "runtime"
    "strings"
    "time"
)

// copy the model from above

func Explain(variable interface{}) {
    _, file, line, _ := runtime.Caller(1)
    //res, _ := json.MarshalIndent(variable, "   ", "  ")
    res := pretty.Formatter(variable)
    fmt.Printf("%s:%d: %# v\n", file[len(FILE_PATH):], line, res)
    //spew.Dump(variable)
}

func s2a(i interface{}) []interface{} { // taken from https://gist.github.com/tonyhb/5819315
    iVal := reflect.ValueOf(i).Elem()
    //typ := iVal.Type()
    values := make([]interface{}, 0, iVal.NumField())
    for i := 0; i < iVal.NumField(); i++ {
        f := iVal.Field(i)
        //tag := typ.Field(i).Tag.Get("tagname")
        //fmt.Println(tag)
        // name := typ.Field(i).Name
        v := f.Interface()
        switch v.(type) {
        case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, string, []byte, time.Time:
            // do nothing
        // case struct{}: // how to catch any embeeded struct?
        case Model: // Model (or any embedded/nameless struct) should also converted to array
            //arr := s2a() // invalid type assertion: f.(Model) (non-interface type reflect.Value on left)
            //arr := s2a(f.Addr().(&Model)) // invalid type assertion: f.Addr().(&Model) (non-interface type reflect.Value on left)
            // umm.. how to convert f back to Model?
            //for _, e := range arr {
                values = append(values, e)
            //}
        default: // struct? but also interface and map T_T
            //v = s2a(&v)
        }
        values = append(values, v)
    }
    return values
}

func main() {
    //sess, err := mgo.Dial("127.0.0.1")
    //Check(err, "unable to connect")
    //db := sess.DB("test")
    //coll := db.C("coll1")
    user := User{}
    user.Id = bson.NewObjectId()
    user.Name = "kis"
    //changeInfo, err := coll.UpsertId(user.Id, user)
    //Check(err, "failed to insert")
    //Explain(changeInfo)
    //Explain(s2a(changeInfo))
    user.Name = "test"
    Explain(user)
    Explain(s2a(&user))
    //err = coll.FindId(user.Id).One(&user)
    //Check(err, "failed to fetch")
    //Explain(user)
    //Explain(s2a(&user))
    user.CreatedAt = time.Now()
    //err = coll.UpdateId(user.Id, user)
    //Check(err, "failed to update")
    Explain(changeInfo)
    Explain(s2a(&user))
    user.CreatedAt = user.DeletedAt
    //err = coll.FindId(user.Id).One(&user)
    //Check(err, "failed to fetch")
    Explain(user)
    Explain(s2a(&user))
}

是否有简单/快速的方法将结构转换为数组(如果结构嵌入/内部,也转换为数组)?

最佳答案

如果您愿意为数组表示中的字段指定固定顺序,您可以通过实现 json.Marshaler interface 来实现自定义其表示。例如:

func (u User) MarshalJSON() ([]byte, error) {
    a := []interface{}{
        u.Name,
        u.Id,
        ...,
    }
    return json.Marshal(a)
}

现在,当您编码这种类型的变量时,它们将被表示为一个数组。如果你还想做相反的事情(将数组解码到这个结构中),你还需要实现 json.Unmarshaler interface .这可以以类似的方式完成,使用 json.Unmarshal 解码为 []interface{} slice ,然后提取值。确保 UnmarshalJSON 被声明为采用指针接收器,否则您的代码将无法工作(您最终将更新结构的副本而不是结构本身)。

关于arrays - Golang,将嵌入式结构转换为数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27141037/

相关文章:

c - 为什么结构的 tagName 经常与 typedef 的名称不同?

python - 第二维为空的 numpy 数组

sql - Postgres WHERE 两个数组有一个非空的交集

c - 在函数 strcmp 中使用节点

interface - 在 Go 中的结构中使用接口(interface)

php - 文件或数据库用于快速读取、不频繁更新/插入?

arrays - swift 3 : Find index and remove an item from array inside an array of Structs

java - 如何计算大于平均数的百分比?

json - 过滤嵌套的 API 响应数据以输出 JSON

ios - 无法从 URL objective-c 获取 NSData