dongxing7318 2018-10-24 07:30
浏览 34
已采纳

存储有关结构的信息/参考

I am looking for a way to store information which struct a function should use. Each struct corresponds to certain database 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
}

I want to be able to dynamically choose struct for 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
}

Goal DRY (I have about 30 tables, function is the same)

I have tried:

  • to use reflect.TypeOf(), but I do not understand if/how I can use it (reflect.Type) to define a new variable

  • Define Record with XormStruct interface{} and for each ListOfTables entry create a slice e.g. var posts []Post and {"Post", "post_id", posts},

  • Searching SO and godocs

It seems to me, that xorm.Find() is not "happy" about getting an interface{} instead of []Posts even if it does not say so.

UPDATE: I believe the breaking difference is this:

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

SOLUTION

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

1条回答 默认 最新

  • dsgni26260 2018-10-24 09:08
    关注

    You may use 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(), or obtain the type descriptor of the slice value in the first place.

    If you store refect.Type values of your tables, this is how you can use it:

    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
    }
    

    Note you must use exported fields!

    And then handling the tables:

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

    You can see a working example (proof of concept) of this (without xorm as that is not available on the Go Playground) using JSON: Go Playground.

    If you were to store reflect.Type values of slices in the first place:

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

    And using it is also simpler:

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

    See proof of concept of this: Go Playground.

    Note that if Record holds slice types (in the field XormStruct), should you ever need to access the type of the struct (the element type of the struct), you may use Type.Elem() for that.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥30 YOLO检测微调结果p为1
  • ¥20 求快手直播间榜单匿名采集ID用户名简单能学会的
  • ¥15 DS18B20内部ADC模数转换器
  • ¥15 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题