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.

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

报告相同问题?

悬赏问题

  • ¥15 yolov8边框坐标
  • ¥15 matlab中使用gurobi时报错
  • ¥15 WPF 大屏看板表格背景图片设置
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真