我有一个这样的结构:
type Game struct {
ID bson.ObjectId
Type string
Location string
Details interface{}
}
type FeudDetails struct {
...
}
type TriviaDetails struct {
...
}
type BingoDetails struct {
...
}我希望使用Type字段Game将Details反序列化为特定类型(如FeudDetails或BingoDetails的实例)。它仍然是interface{} in Game,但是我可以这样做:
feudDetails, ok := game.Details.(FeudDetails)
if ok {
// we know this is a Feud game, and we have the details
feudDetails.Round++
}医生们说“可以使用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
}我这里有一个堆栈溢出。我认为这是因为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.”
编辑:I也尝试过正常反序列化,然后使用game.Details.(FeudDetails)转换Details的interface{}版本,但转换失败。我想我不能这样做,因为非序列化后的底层类型不是FeudDetails,而是map[string]interface{}。
编辑2:我认为我很聪明,在从数据库检索时(在调用db...One(&game)之前的game := Game{Details: FeudDetails: {}}),我会用正确的类型预先填充一个对象,但我的诡计没有奏效:
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发布于 2020-04-02 21:40:11
在(Un)编组期间忽略Details
更改Game的定义,这样bson就不会尝试使用Details字段做任何事情:
type Game struct {
...
Details interface{} `json:"details" bson:"-"`
}手工解封Details
func (game *Game) SetBSON(r bson.Raw) error {
// Unmarshall everything except Details
type tempGame Game
err := r.Unmarshal((*tempGame)(game)) // this is necessary to prevent recursion
if err != nil {
return err
}
// Get the raw data for Details
var d struct {
Details bson.Raw
}
if err := r.Unmarshal(&d); err != nil {
return err
}
gameType, ok := games[game.Type]
if ok {
// Use individual processing based on game Type
game.Details, err = gameType.LoadDetails(d.Details)
if err != nil {
return err
}
// fmt.Sprintf("%T", game.Details) => main.FeudDetails
}
return nil
}Details元帅手工
据我所知,在我们让bson在原始结构中省略它之后,让它包含Details的唯一方法是创建一个完整的其他结构,逐个复制数据,并在GetBSON中使用该类型。看来一定有更好的办法。
https://stackoverflow.com/questions/60961641
复制相似问题