-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Proposal Details
I'm aware of #63397, but here is a simple approach which I want to use.
I want to use "struct" for defining API responses. But the API is so complicated that some of fields in that "struct" are conditionally initialized (i.e. needs to hide fields when values are not assigned). But due to golang's zero values, I can't hide fields in that "struct".
As a result, I'm currently using "map[string]any" instead of "struct" in order to make sure that only fields that have values defined (they might be golang's zero values) are included in the API responses. But since "struct" is more easy to understand, I want to make it possible to hide fields in a "struct" when values are not assigned.
The diff for json package and an example usage of this proposal are shown below.
--- a/json/encode.go
+++ b/json/encode.go
@@ -727,6 +727,10 @@ type structFields struct {
nameIndex map[string]int
}
+type ValueDefinedTester interface {
+ IsDefined() bool
+}
+
func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
next := byte('{')
FieldLoop:
@@ -748,6 +752,9 @@ FieldLoop:
if f.omitEmpty && isEmptyValue(fv) {
continue
}
+ if vdt, ok := fv.Interface().(ValueDefinedTester); ok && !vdt.IsDefined() {
+ continue
+ }
e.WriteByte(next)
next = ','
if opts.escapeHTML {
package main
import (
"encoding/json"
"fmt"
)
type MyInt32 struct {
intValue int32
isNull bool
isDefined bool
}
func (t MyInt32) IsDefined() bool {
return t.isDefined
}
func (t MyInt32) MarshalJSON() ([]byte, error) {
if t.isNull {
return []byte("null"), nil
} else {
return []byte(fmt.Sprint(t.intValue)), nil
}
}
func (t MyInt32) GetValue() int32 {
return t.intValue
}
func (t *MyInt32) SetValue(v int32) {
t.intValue = v
t.isNull = false
t.isDefined = true
}
func (t MyInt32) IsNull() bool {
return t.isNull
}
func (t *MyInt32) SetNull() {
t.intValue = 0
t.isNull = true
t.isDefined = true
}
func (t *MyInt32) Reset() {
t.intValue = 0
t.isNull = false
t.isDefined = false
}
func main() {
type MyStruct struct {
I MyInt32
}
var s MyStruct
s.I.SetValue(100) // => {"I":100}
s.I.SetNull() // => {"I":null}
s.I.Reset() // => {}
if out, err := json.Marshal(s); err == nil {
fmt.Println(string(out))
}
}
Metadata
Metadata
Assignees
Labels
Type
Projects
Status