我正在尝试使用 Go 来查看是否可以将当前项目转移到它。我当前的非 Go 代码库中有几个域模型,它们利用基于类型字段的多态性。
关于该主题的文档或文献并不多,而我一天左右的学习时间使遍历和研究其来源有点……好吧,我来了。
反正...
以下是基本接口和实现结构的示例:
package model
type Filter interface {
SetType(t enum.FilterType)
}
type Base struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Type enum.FilterType `json:"type,omitempty" bson:"type,omitempty"`
}
func (bf *Base) SetType(t enum.FilterType) {
bf.Type = t
}
type ExampleA struct {
Base `bson:"inline"`
AField string `bson:"aField,omitempty" json:"aField,omitempty"`
}
type ExampleB struct {
Base `bson:"inline"`
BField string `bson:"bField,omitempty" json:"bField,omitempty"`
}
它将有许多结构实现,因此我需要能够基于字段type中的字段执行切换,bson.Raw然后才能确定struct要使用哪个。
据我所知,RegisterHookDecoder[ docs ] [ source ] 正是我所需要的。但是,我无法让它真正启动,我不知道为什么。
解码器:
type filterDecoder struct {}
func (d filterDecoder) DecodeValue(ctx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
fmt.Println("Inside DecodeValue")
return nil
}
package main
func main() {
ctx := context.TODO()
// I'm not sure this is right. I'm trying to get the type of model.Filter so that I can register the HookDecoder against it.
filterType := reflect.TypeOf((*model.Filter)(nil)).Elem()
rb := bsoncodec.NewRegistryBuilder()
rb.RegisterHookDecoder(filterType, filterDecoder{})
// so far as I can tell, these are required. Otherwise I get the error:
// "cannot transform type primitive.D to a BSON Document: no encoder found for primitive.D"
// I haven't seen this approach implemented anywhere aside from the source.
// I'm not sure if this is overriding my hook? changing the order to have
// rb.RegisterHookDecoder(...) below/above these does not have an impact.
bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb)
bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb)
client, err := mongo.Connect(ctx,
options.Client().
ApplyURI("mongodb://localhost:27017").
SetRegistry(rb.Build()),
)
col := client.Database("LearningGo").Collection("filters")
cursor, err := col.Find(ctx, bson.M{})
if err != nil {
panic(err)
}
for cursor.Next(ctx) {
var filter model.Filter
cursor.Decode(filter)
}
}
我真的不确定我在这里缺少什么。我在明显的事情上犯错了吗?
LookupDecoder(filterType)ValueDecoderFunc实际上根据下面的代码找到了一个。我只是不确定这是否是一个包罗万象的东西。我对 Go 的了解还远远不够,无法断言更多。
vd,err := newRegistry.LookupDecoder(filterType)
fmt.Println(reflect.TypeOf(vd).Name())
无论如何,我感谢您阅读本文。感谢您的时间。
**编辑:更新以反映@icza 建议的更改