12 Matching Annotations
  1. May 2021
    1. Interface values encode as the value contained in the interface. A nil interface value encodes as the null JSON value.

      接口值 json 化其内部值,nil 接口 json 化为 json null。

    2. Pointer values encode as the value pointed to. A nil pointer encodes as the null JSON value.

      指针值 json 化其指向的值。空指针被 json 化为 json null。

    3. Map values encode as JSON objects.

      这里主要谈 go map values json 化时,对于 key 的处理。值的处理和上面讲的一样。讲真,我觉得实际情况下用 string 和 integer 类型就够了,都被当成 json string key。

    4. The Go visibility rules for struct fields are amended for JSON when deciding which field to marshal or unmarshal. If there are multiple fields at the same level, and that level is the least nested (and would therefore be the nesting level selected by the usual Go rules), the following extra rules apply: 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, even if there are multiple untagged fields that would otherwise conflict. 2) If there is exactly one field (tagged or not according to the first rule), that is selected. 3) Otherwise there are multiple fields, and all are ignored; no error occurs.

      这段主要解释嵌套匿名结构在 marshal or unmarshal 时,field key 的冲突情况。我把 untagged 域 json 化的 key 称为 field key,tagged 域 json 化的 key 称为 tag key。

      注意:这里讲的 tagged 域是指设置了 key name 的 tag,没有设置 key name 的 tagged 域在 json 化中使用的还是 filed key。

      本段涉及的域处在同一层级,且该层级至少是一层嵌套层。

      # 至少是这样的嵌套
      type A struct {
          Name string
      }
      
      type B struct {
          Name string
      }
      
      type C struct {
          Name string
      }
      
      type D struct {
          A
          B
          C
      }
      
      func TestFeature(t *testing.T) {
          d := D{A{"A"}, B{"B"}, C{"C"}}
          r, _ := json.Marshal(d)
          fmt.Println(string(r))
      }
      

      以上 D struct 的 instance 有多个相同名称的域 Name。在对其做 marshal or unmarshal 时应用以下规则:

      1、json tagged 的域优先于 untagged 的域考虑。

      # 如果 A 的域被 `json:"Name"`,则 B C 里的 Name 域都被忽略。
      {"Name":"A"}
      

      2、如果 tagged 域的 tag key 唯一,则被正常 marshal or unmarshal,否则冲突的 tagged 域都被忽略。如果 untagged 域的 field key 唯一,则被正常 marshal or unmarshal,否则冲突的 untagged 域都被忽略。

      # 如果 A 和 B 的 Name 域都被 `json:"Name"`,则视为  tag key 冲突,所以两者都被忽略。并且 C 的 Name 域为 untagged,所以 C instance 在这场“Name 域 json 化争夺战”中完全处于下风。最终这场战斗没有人胜出。
      # {}
      
      # 如果 A 的 Name 域被 `json:"Nickname"`,则剩下 B C 两个 untagged 域争夺,根据规则,最终没有在 json string 中见到 Name key。
      # {"Nickname":"A"}
      
    5. Anonymous struct fields

      首先要明白什么是 anonymous struct field,看这里。

      看过上面文章,应该对 anonymous struct field 及其规则有大致的了解。

      在对 anonymous struct field 做 json encoding 时,anonymous struct field 中的 exported field 默认会被当做 outer struct 的 field 来 encoding。

      如果对匿名结构域使用 json tag 功能给予 key name,则在 encoding 时不会被当作匿名结构域应用上述规则。

      如果匿名结构域是 interface{} 类型,则也不会被当作匿名结构域应用上述规则,interface{} 的名称会被当作 key name。

      举例:

      type Kitchen struct {
          NumOfPlates uint
      }
      
      type Door interface {
          echo()
      }
      
      type FrontDoor struct {
          Name string
      }
      
      func (frontDoor *FrontDoor) echo() {
          fmt.Println("I'm " + frontDoor.Name)
      }
      
      type House struct {
          Kitchen    `json:"kitchen"`
          NumOfRooms uint
          Door
      }
      
      func main() {
      
          h := House{Kitchen{10}, 3, &FrontDoor{"Gold Door"}}
      
          sp, _ := json.Marshal(h)
          fmt.Println(string(sp))
      }
      # {"kitchen":{"NumOfPlates":10},"NumOfRooms":3,"Door":{"Name":"Gold Door"}}
      # 正常被当作匿名结构域 encoding json 时:
      # {"NumOfPlates":10,"NumOfRooms":3}
      
    6. Floating point, integer, and Number values encode as JSON numbers.

      所以 go 中的数值类型在 encoding 为 json 时不用考虑太多,它们都会被 encoding 为 json number。

    7. []byte encodes as a base64-encoded string, and a nil slice encodes as the null JSON value.
      type Person struct {
          Name        string
          Age         uint
          Married     bool
          Hobbies     []string
          Family      []Person
          Friends     []Person
          BytesOfName []byte
      }
      
      func main() {
      
          p := Person{
              Name:        "Bob",
              Age:         30,
              Married:     true,
              Hobbies:     []string{"Baseball", "Running", "Gaming"},
              Family:      nil,
              Friends:     []Person{},
              BytesOfName: []byte("Bob"),
          }
          sp, _ := json.Marshal(p)
          fmt.Println(string(sp))
      }
      # {"Name":"Bob","Age":30,"Married":true,"Hobbies":["Baseball","Running","Gaming"],"Family":null,"Friends":[],"BytesOfName":"Qm9i"}
      
    8. The encoding of each struct field can be customized by the format string stored under the "json" key in the struct field's tag.

      struct field 的 json encoding 行为可以通过 json tag 自定义,格式为:json:"keyName,option1,..."

      以下是一些使用情况介绍:

      1、即想使用 json tag 定义行为又要使用 struct field name 来作为 json key:json:",option1,..."

      2、使用 omitempty 选项可以忽略该 field 的 json encoding,如果该 field 的值是空值的话。

      3、使用 json:"-" 的 field 在 encoding 时被忽略。如果想要使用 "-" 做为 json key,那么在 "-" 后加上一个 comma 即可:json:"-,"

      4、如果你想要一些非 string 的类型被 encoding 为 json string,使用 json:",string" 标签选项即可。

      type Person struct {
          Age uint `json:",string"`
      }
      
      func main() {
          p := Person{
              23,
          }
          sp, _ := json.Marshal(p)
          fmt.Println(string(sp))
      }
      # {"Age":"23"}
      
    9. key name

      这里的 key name 不知道指什么,如果指的是 json tag 里给的 key name,那么在上面已经介绍过了,这里难道只再提一下作为 key name 的规则吗?

    10. Struct values encode as JSON objects

      struct 对应 json objects。每个 exported field 对应 json object 中的一个 member,默认 field name 作为 key。

    11. String values encode as JSON strings coerced to valid UTF-8, replacing invalid bytes with the Unicode replacement rune. So that the JSON will be safe to embed inside HTML <script> tags, the string is encoded using HTMLEscape, which replaces "<", ">", "&", U+2028, and U+2029 are escaped to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029". This replacement can be disabled when using an Encoder, by calling SetEscapeHTML(false).

      知道 go string values encoded as json strings 就行了。

    12. Marshal traverses the value v recursively. If an encountered value implements the Marshaler interface and is not a nil pointer, Marshal calls its MarshalJSON method to produce JSON. If no MarshalJSON method is present but the value implements encoding.TextMarshaler instead, Marshal calls its MarshalText method and encodes the result as a JSON string. The nil pointer exception is not strictly necessary but mimics a similar, necessary exception in the behavior of UnmarshalJSON.

      如果 v 实现了 Marshaler 接口或者实现了 encoding,则该方法会调用 MarshalJSON 方法或者 TextMarshaler 方法来完成 json encoding 工作。否则使用默认的 json encoding 规则:type-dependent default encodings。