【发布时间】:2020-04-03 05:40:11
【问题描述】:
可能相关:How to use interface type as a model in mgo (Go)?
我有一个这样的结构:
type Game struct {
ID bson.ObjectId
Type string
Location string
Details interface{}
}
type FeudDetails struct {
...
}
type TriviaDetails struct {
...
}
type BingoDetails struct {
...
}
我想使用Game 的Type 字段将Details 反序列化为特定类型(如FeudDetails 或BingoDetails 的实例)。在Game 中它仍然是interface{},但我可以这样做:
feudDetails, ok := game.Details.(FeudDetails)
if ok {
// we know this is a Feud game, and we have the details
feudDetails.Round++
}
The docs 说“可以使用 bson.Raw 部分解组或编组值”,但他们没有提供我能找到的任何示例。
我尝试过使用:
func (game *Game) SetBSON(r bson.Raw) error {
err := r.Unserialize(game)
if err != nil {
return nil
}
games[game.Type].LoadDetails(game) // this calls a function based on the Type to
// create a concrete value for that game.
return nil
}
我在这里得到一个 (ahem) 堆栈溢出。我认为这是因为r.Unserialize 递归调用SetBSON。
我的目标是对所有字段除了 Details 使用标准反序列化,然后能够使用game.Type 来确定如何处理Details。如果我这样做:
type GameDetails interface{}
type Game struct {
...
Details GameDetails
}
func (details *GameDetails) SetBSON(r bson.Raw) error {
// game isn't defined
games[game.Type].LoadDetails(r, details)
}
那么我如何访问外部Type 字段以了解将其反序列化为哪种游戏类型?
我也会接受“你做错了,Go 中一个更好的模式是 XYZ...”的答案。
编辑:我也尝试正常反序列化,然后使用game.Details.(FeudDetails) 转换interface{} 的interface{} 版本,但转换失败。我想我不能那样做,因为反序列化后的底层类型不是FeudDetails,而可能是map[string]interface{}。
编辑 2: 我认为我会很聪明,并在从数据库中检索时使用正确的类型预先填充一个对象(在调用 db...One(&game) 之前),但我的诡计确实做到了不工作:
DEBU[Mar 31 22:19:09.442] Caching show gid=5e814448ef5b9858b7ff4e57
TRAC[Mar 31 22:19:09.442] Before database call dtype=main.FeudDetails
TRAC[Mar 31 22:19:09.446] After database call dtype=bson.M
【问题讨论】:
-
我想我找到了一个可能的解决方案(它是 JSON,但它可能对 BSON 有效)。我会将它改编为我的代码,如果它有效,我会将其发布为答案:stackoverflow.com/questions/53453782/…