Go에서 양방향 목록을 JSON으로 변환 할 때 비틀림

11750 단어 5JSON

무엇이 있었는지



Go로 코딩하는 동안, 양방향 리스트 같은 것을 자작&JSON으로 변환할 필요성이 있었다. 정책으로서는 encoding/json 를 사용해 몇 가지 생각이, 엉망이 막혀 버렸다, 라고 하는 이야기.

요컨대


  • struct에 자신이있을 때 제대로 포인터로합시다
  • JSON으로 변환 할 때 그 녀석이 순환 할 수 있다면 json:"-"에서 무시하고 차단하십시오

  • struct에 자신이 있으면 invalid recursive type



    당연히 당연한 이야기입니다만.

    실패편


    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
    )
    
    type Person struct {
        Name   string
        Parent Person
        Child  Person
    }
    
    func main() {
        sora := Person{}
        sora.Name = "Sora Amamiya"
        j, err := json.Marshal(sora)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(string(j))
    }
    

    이렇게 화가납니다.
    $ go run main.go
    # command-line-arguments
    ./main.go:9:6: invalid recursive type Person
    

    그럼 그렇다고 하는 느낌. 상호 재귀에서도 화내는 것 같습니다. 우수.

    성공편



    포인터로 고쳐 해결.
    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
    )
    
    type Person struct {
        Name   string
        Parent *Person
        Child  *Person
    }
    
    func main() {
        sora := Person{}
        sora.Name = "Sora Amamiya"
        j, err := json.Marshal(sora)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(string(j))
    }
    
    $ go run main.go
    {"Name":"Sora Amamiya","Parent":null,"Child":null}
    

    JSON 순환 차단



    본제입니다.
    원래 양방향 목록을 JSON으로 바꾸고 싶은 것이 얼마나 있는지 궁금합니다.
    Person의 구조는 이전과 동일합니다. 이런 느낌에 작은 양방향 목록을 결합합니다.



    실패편


    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
    )
    
    type Person struct {
        Name   string  `json:"name"`
        Parent *Person 
        Child  *Person `json:"child"`
    }
    
    
    func main() {
        m := Person{}
        n := Person{}
        m.Name = "Momo Asakura"
        m.Child = &n
        n.Name = "Shiina Natsukawa"
        n.Parent = &m
    
        j, err := json.Marshal([]Person{m, n})
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(string(j))
    }
    

    출력은 이런 느낌으로 말 그대로 무한히 화나게 됩니다. 재귀 오류입니다.
    runtime: goroutine stack exceeds 1000000000-byte limit
    fatal error: stack overflow
    
    runtime stack:
    runtime.throw(0x4f30b2, 0xe)
            /usr/local/go/src/runtime/panic.go:774 +0x72
    runtime.newstack()
            /usr/local/go/src/runtime/stack.go:1046 +0x6e9
    runtime.morestack()
            /usr/local/go/src/runtime/asm_amd64.s:449 +0x8f
    
    goroutine 1 [running]:
    encoding/json.stringEncoder(0xc00007c000, 0x4c8f80, 0xc00000c080, 0x198, 0x100)
            /usr/local/go/src/encoding/json/encode.go:589 +0x389 fp=0xc02009a380 sp=0xc02009a378 pc=0x4a94c9
    encoding/json.structEncoder.encode(0xc000082000, 0x3, 0x4, 0xc00005e2a0, 0xc00007c000, 0x4dcee0, 0xc00000c
    

    그건 당연합니다. "Parent에 JSON 태그를 붙이지 않으면 원찬 무시해 주지 않을까?"라는 얕은 생각을 한 것이 안된다. 디폴트로 필드명을 그대로 사용해 변환해 줍니다. 매우 우수한 라이브러리.

    성공편



    즉 내가 하고 싶은 것은 「JSON 라이브러리로 임의의 필드를 무시한다」라고 하는 것.
    이렇게 하려면 태그를 json:"-"로 지정합니다.
    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
    )
    
    type Person struct {
        Name   string  `json:"name"`
        Parent *Person `json:"-"`
        Child  *Person `json:"child"`
    }
    
    func main() {
        m := Person{}
        n := Person{}
        m.Name = "Momo Asakura"
        m.Child = &n
        n.Name = "Shiina Natsukawa"
        n.Parent = &m
    
        j, err := json.Marshal([]Person{m, n})
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(string(j))
    }
    

    출력 결과는 이쪽. 제대로 Child만 가지고 있어요. Root에서 당긴다면 Parent는 따로 낼 필요 없으니까요.
    $ go run main.go
    [{"name":"Momo Asakura","child":{"name":"Shiina Natsukawa","child":null}},{"name":"Shiina Natsukawa","chil
    d":null}]
    

    요약


  • Go, 쓰기 쉽고 멋지다.
  • JSON으로 바꾸기 쉽고 멋집니다.
  • 포인터 의식하지 않아서 좋은 언어를 사용하고 있는 사람만은 포인터 배우게 되 떠올리게 하자.
  • 모두 Go 하자, 즐겁다 (초보자 병감).
  • 좋은 웹페이지 즐겨찾기