存储 information/reference 左右结构

Store information/reference about structure

我正在寻找一种方法来存储结构函数应该使用的信息。每个结构体对应某个数据库table.

type Record struct {
   TableName string
   PrimaryKey string
   //XormStruct // how can I store User or Post here?
   XormStruct2 interface{} // see I have tried below
   XormStruct3 reflect.Type // see I have tried below
}

var posts []Post

var ListOfTables [...]Record {
   {"User", "id", User},
   //{"Post", "post_id", Post},
   {"Post", "post_id", posts, reflect.TypeOf([]Post{})},
}

// User is xorm struct
type User struct {
   Id int64
   Name string
}

// Post is xorm struct
type Post struct {
   Post_id int64
   Name string
   Other string
}

我希望能够为 table 动态选择结构。

for _, rec := range ListOfTables {
    //var entries []rec.XormStruct // this does not work, of course
    //var entries []reflect.TypeOf(rec.XormStruct) // this does not work either
    // xorm is *xorm.Engine
    xorm.Find(&entries)
    //xorm.Find(&rec.XormStruct2) //with interface{}, does not work - produces an empty &[]
    posts3 := reflect.New(rec.XormStruct3).Interface()
    //xorm.Find(&posts3) // same as above, produces empty &[]
    var posts []Post
    xorm.Find(&posts) // produces desired data

    // afterwards I will do same to any table entries, e.g.
    xml.Marshal(entries)
    // so there is really no need to create identical functions for each table
}

目标 DRY(我有大约 30 tables,功能相同)

我试过:

在我看来,xorm.Find() 并不是 "happy" 获得 interface{} 而不是 []Posts,即使它没有这么说。

更新: 我相信最大的区别是:

spew.Dump(posts3) //posts3 := reflect.New(rec.XormStruct3).Interface()
// (*[]main.Post)<0x2312312>(<nil>)
spew.Dump(posts) //var posts []Post
// ([]main.Post)<nil>

解决方案

posts3 := reflect.New(rec.XormStruct3).Interface()
xorm.Find(posts3) // not &posts3

可以使用reflect.Type to represent / describe a Go type. And at runtime, you may use reflect.New() to obtain a pointer to the zeroed value of this type wrapped in a reflect.Value. And if you need a slice instead of a single value, you may use reflect.SliceOf(),或者先获取切片值的类型描述符

如果您存储表的 refect.Type 个值,您可以这样使用它:

type Record struct {
   TableName  string
   PrimaryKey string
   XormStruct reflect.Type
}

var ListOfTables [...]Record {
   {"User", "id", reflect.TypeOf((*User)(nil)).Elem()},
   {"Post", "post_id", reflect.TypeOf((*Post)(nil)).Elem()},
}

// User is xorm struct
type User struct {
   Id   int64
   Name string
}

// Post is xorm struct
type Post struct {
   Post_id int64
   Name    string
   Other   string
}

注意你必须使用导出字段!

然后处理表格:

for _, rec := range ListOfTables {
    entries := reflect.New(reflect.SliceOf(t.XormStruct)).Interface()
    err := xorm.Find(entries)
    // Handle error

    err := xml.Marshal(entries)
    // Handle error
}

您可以使用 JSON 查看此的工作示例(概念证明)(没有 xorm,因为它在 Go Playground 上不可用):Go Playground.

如果您首先要存储切片的 reflect.Type 个值:

var ListOfTables [...]Record {
   {"User", "id", reflect.TypeOf([]User{})},
   {"Post", "post_id", reflect.TypeOf([]Post{})},
}

而且使用起来也更简单:

for _, rec := range ListOfTables {
    entries := reflect.New(t.XormStruct).Interface()
    err := xorm.Find(entries)
    // Handle error

    err := xml.Marshal(entries)
    // Handle error
}

查看此概念的证明:Go Playground

请注意,如果 Record 包含切片类型(在字段 XormStruct 中),如果您需要访问结构的类型(结构的元素类型),您可以使用Type.Elem() 为此。