我有一个类型为 foo 的对象,其中包含一个接口 ActivationInterface ;该对象保存在 MongoDB 中,由于内部对象的基础类型未知,我无法将其取回。
我按如下方式实现了 UnmarshalBSON 但没有成功,因为即使在设置了接口的具体类型之后,解组器现在仍然执行底层类型,因为我仍然收到错误: 解码关键行为错误:找不到 main.ActivationInterface 的解码器
你知道我怎样才能实现这个目标吗?
我在这里发现了一些接近工作的东西,所以我不明白为什么我的不是:基于类型键解组动态 JSON 我看不出我做错了什么,有什么不同......!
编辑:我更新了代码以与 json 进行比较。 UnmarshalJSON 使用完全相同的代码工作得很好,而 UnmarshalBSON 仍然失败。
package main
import (
"fmt"
"log"
"go.mongodb.org/mongo-driver/bson"
)
type foo struct {
Type string `bson:"type"`
Act ActivationInterface
}
type ActivationInterface interface{}
type Activation1 struct {
Name string `bson:"name"`
}
type Activation2 struct {
Address string `bson:"adress"`
}
func (q *foo) UnmarshalBSON(data []byte) error {
// Unmarshall only the type
fooTemp := new(struct {
Type string `bson:"type"`
})
if err := bson.Unmarshal(data, fooTemp); err != nil {
return err
}
fmt.Println(fooTemp.Type)
// Set the type to the prop
switch fooTemp.Type {
case "act1":
// q.Act = &Activation1{}
q.Act = new(Activation1)
case "act2":
// q.Act = &Activation2{}
q.Act = new(Activation2)
default:
fmt.Println("DEFAULT")
}
// Call Unmarshal again
type Alias foo // avoids infinite recursion using a type alias
return bson.Unmarshal(data, (*Alias)(q))
}
func main() {
foo1 := foo{
Type: "act1",
Act: Activation1{
Name: "name: act1",
},
}
foo2 := foo{
Type: "act2",
Act: Activation2{
Address: "adress: act2",
},
}
// Marshal
m1, err := bson.Marshal(foo1)
if err != nil {
log.Fatal(err)
}
m2, err := bson.Marshal(foo2)
if err != nil {
log.Fatal(err)
}
//fmt.Println(m1, m2)
// Unmarshal
var u1, u2 foo
err = bson.Unmarshal(m1, &u1)
if err != nil {
fmt.Println("1 -> ", err) // error decoding key act: no decoder found for main.ActivationInterface
}
err = bson.Unmarshal(m2, &u2)
if err != nil {
fmt.Println("2 -> ", err) // error decoding key act: no decoder found for main.ActivationInterface
}
fmt.Println(foo1.Type, ":", u1.Act.(*Activation1).Name)
fmt.Println(foo2.Type, ":", u2.Act.(*Activation2).Address)
}
去游乐场:https://go.dev/play/p/bHMy6-ZLsYQ
几乎相同的代码,但使用 JSON 并工作:https://go.dev/play/p/V5HLrQ_-ls3
谢谢!
在结构中使用接口时,解组无法确定要选择哪个“实现”...您必须根据“类型”字段手动执行此操作。通常,unmarshall 方法会放置一个接口{} 的映射,即键值存储。 无论如何,回到你的问题,你必须将接口数据存储在 bson.Raw (字节片)中,并通过选择正确的结构手动进行解组。
package main
import (
"fmt"
"log"
"go.mongodb.org/mongo-driver/bson"
)
type foo struct {
Type string `bson:"type"`
Act ActivationInterface
}
type ActivationInterface interface{}
type Activation1 struct {
Name string `bson:"name"`
}
type Activation2 struct {
Address string `bson:"adress"`
}
func (q *foo) UnmarshalBSON(data []byte) error {
// Unmarshall only the type
fooTemp := new(struct {
Type string `bson:"type"`
Act bson.Raw
})
if err := bson.Unmarshal(data, fooTemp); err != nil {
return err
}
fmt.Println(fooTemp.Type)
// Set the type to the prop
switch fooTemp.Type {
case "act1":
// q.Act = &Activation1{}
a := Activation1{}
err := bson.Unmarshal(fooTemp.Act, &a)
if err != nil {
return err
}
q.Act = a
case "act2":
// q.Act = &Activation2{}
a := Activation2{}
err := bson.Unmarshal(fooTemp.Act, &a)
if err != nil {
return err
}
q.Act = a
default:
fmt.Println("DEFAULT")
return fmt.Errorf("unknown type: %v", fooTemp.Type)
}
return nil
}
func main() {
foo1 := foo{
Type: "act1",
Act: Activation1{
Name: "name: act1",
},
}
foo2 := foo{
Type: "act2",
Act: Activation2{
Address: "adress: act2",
},
}
// Marshal
m1, err := bson.Marshal(foo1)
if err != nil {
log.Fatal(err)
}
m2, err := bson.Marshal(foo2)
if err != nil {
log.Fatal(err)
}
//fmt.Println(m1, m2)
// Unmarshal
var u1, u2 foo
err = bson.Unmarshal(m1, &u1)
if err != nil {
fmt.Println("1 -> ", err) // error decoding key act: no decoder found for main.ActivationInterface
}
err = bson.Unmarshal(m2, &u2)
if err != nil {
fmt.Println("2 -> ", err) // error decoding key act: no decoder found for main.ActivationInterface
}
fmt.Println(foo1.Type, ":", u1.Act.(Activation1).Name)
fmt.Println(foo2.Type, ":", u2.Act.(Activation2).Address)
}