| @@ -72,3 +72,12 @@ func SplitN[T constraints.Integer](v T, n int) []T { | |||||
| return result | return result | ||||
| } | } | ||||
| // 除法,如果除数为0,则返回默认值 | |||||
| func DivOrDefault[T constraints.Integer | constraints.Float](v, d T, def T) T { | |||||
| if d == 0 { | |||||
| return def | |||||
| } | |||||
| return v / d | |||||
| } | |||||
| @@ -65,6 +65,9 @@ func JSONToObjectExRaw(data []byte, ret any) error { | |||||
| } | } | ||||
| // 将JSON字符串转为对象。支持TypeUnion。 | // 将JSON字符串转为对象。支持TypeUnion。 | ||||
| // | |||||
| // 如果发现反序列化后的结果不对,但没有返回错误,可以考虑是JSON字符串有问题, | |||||
| // 尤其是在反序列化嵌套的TypeUnion时,如果内部的TypeUnion反序列化失败,错误是不会传递出来的(库的缺陷) | |||||
| func JSONToObjectStreamEx[T any](stream io.Reader) (T, error) { | func JSONToObjectStreamEx[T any](stream io.Reader) (T, error) { | ||||
| var ret T | var ret T | ||||
| dec := defaultAPI.NewDecoder(stream) | dec := defaultAPI.NewDecoder(stream) | ||||
| @@ -665,3 +665,32 @@ func Test_ObjectToJSON3(t *testing.T) { | |||||
| // So(ret, ShouldResemble, val) | // So(ret, ShouldResemble, val) | ||||
| }) | }) | ||||
| } | } | ||||
| type BaseCallback interface{} | |||||
| type StCallback struct { | |||||
| Metadata `union:"StCallback"` | |||||
| Type string | |||||
| Value string | |||||
| } | |||||
| func (st *StCallback) OnUnionSerializing() { | |||||
| st.Value = "called" | |||||
| st.Type = "StCallback" | |||||
| } | |||||
| func Test_ObjectToJSONEx4(t *testing.T) { | |||||
| Convey("序列化Callback", t, func() { | |||||
| union := types.NewTypeUnion[BaseCallback](&StCallback{}) | |||||
| UseTypeUnionInternallyTagged(&union, "Type") | |||||
| val := []BaseCallback{&StCallback{}} | |||||
| data, err := ObjectToJSONEx(val) | |||||
| So(err, ShouldBeNil) | |||||
| ret, err := JSONToObjectEx[[]BaseCallback](data) | |||||
| So(err, ShouldBeNil) | |||||
| So(len(ret), ShouldEqual, 1) | |||||
| So(ret[0].(*StCallback).Value, ShouldEqual, "called") | |||||
| }) | |||||
| } | |||||
| @@ -1,3 +1,7 @@ | |||||
| package types | package types | ||||
| type Metadata struct{} | type Metadata struct{} | ||||
| type OnUnionSerializing interface { | |||||
| OnUnionSerializing() | |||||
| } | |||||
| @@ -8,6 +8,7 @@ import ( | |||||
| jsoniter "github.com/json-iterator/go" | jsoniter "github.com/json-iterator/go" | ||||
| "github.com/modern-go/reflect2" | "github.com/modern-go/reflect2" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/types" | "gitlink.org.cn/cloudream/common/pkgs/types" | ||||
| sertypes "gitlink.org.cn/cloudream/common/utils/serder/types" | |||||
| ref2 "gitlink.org.cn/cloudream/common/utils/reflect2" | ref2 "gitlink.org.cn/cloudream/common/utils/reflect2" | ||||
| ) | ) | ||||
| @@ -211,6 +212,12 @@ func (e *InternallyTaggedEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.St | |||||
| val = reflect2.IFaceToEFace(ptr) | val = reflect2.IFaceToEFace(ptr) | ||||
| } | } | ||||
| if val != nil { | |||||
| if on, ok := val.(sertypes.OnUnionSerializing); ok { | |||||
| on.OnUnionSerializing() | |||||
| } | |||||
| } | |||||
| // 可以考虑检查一下Type字段有没有赋值,没有赋值则将其赋值为union Tag指定的值 | // 可以考虑检查一下Type字段有没有赋值,没有赋值则将其赋值为union Tag指定的值 | ||||
| stream.WriteVal(val) | stream.WriteVal(val) | ||||
| } | } | ||||
| @@ -292,6 +299,10 @@ func (e *ExternallyTaggedEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.St | |||||
| return | return | ||||
| } | } | ||||
| if on, ok := val.(sertypes.OnUnionSerializing); ok { | |||||
| on.OnUnionSerializing() | |||||
| } | |||||
| stream.WriteObjectStart() | stream.WriteObjectStart() | ||||
| valType := ref2.TypeOfValue(val) | valType := ref2.TypeOfValue(val) | ||||
| if !e.union.Union.Include(valType) { | if !e.union.Union.Include(valType) { | ||||