Сохраняющиеся вложенные структуры в Голанге - PullRequest
0 голосов
/ 07 ноября 2018

Я хочу добавить постоянство и инициализацию из json. Я пытаюсь сохранить / загрузить вложенные структуры и получаю «фатальную ошибку: переполнение стека».

Как я понимаю, причина в том, что родительские и дочерние структуры имеют указатели друг на друга, а библиотека json собирается в циклы. Мне нужен указатель на Parent, так как нужен доступ к нему от ребенка.

Я понимаю, что это обычная проблема, как лучше ее решить?

type Mcloud struct {
    Projects map[string]*Project `json:"Projects"`
    Workdir  string
}

type Project struct {
    Name     string
    Networks map[string]Network
    Parent   *Mcloud
    TFC      TFConf
}

func newMcloud() *Mcloud {
    mc := &Mcloud{
        Projects: make(map[string]*Project),
        Workdir:  defaultWorkDir,
    }
    mc.load(statefile)

    return mc
}


func (mc *Mcloud) addProject(n string) {
    mc.Projects[n] = &Project{
        Name:     n,
        Networks: make(map[string]Network),
        Parent:   mc,
    }
    mc.Projects[n].addTFConf()
}

//save saves state to statefile
func (mc *Mcloud) save(f string) (err error) {
    if jsonState, err := json.Marshal(mc); err != nil {
        fmt.Println("Was not able to marshal")
        log.Fatal(err)
    } else {
        if err := ioutil.WriteFile(f, jsonState, 0666); err != nil {
            fmt.Println("Was not able to write state to", f, "!")
            log.Fatal(err)
        }
        fmt.Println("Save function saves: \n", mc, "to file ", f)
    }

    return err
}

func (mc *Mcloud) load(f string) (err error) {
    var bytestate []byte

    if bytestate, err = ioutil.ReadFile(f); err == nil {
        err = json.Unmarshal(bytestate, &mc)
    }

    return err
}

Получение

время выполнения: стек стека превышает 1000000000 байт. Неустранимая ошибка: переполнение стека

стек времени выполнения: runtime.throw (0x149cdfe, 0xe) /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:608 + 0x72 runtime.newstack () /usr/local/Cellar/go/1.11.1/libexec/src/runtime/stack.go:1008 + 0x729 runtime.morestack () /usr/local/Cellar/go/1.11.1/libexec/src/runtime/asm_amd64.s:429 + 0x8f

маршрут 1 [выполняется]: runtime.heapBitsSetType (0xc042a7df20, 0x60, 0x60, 0x1486e60) /usr/local/Cellar/go/1.11.1/libexec/src/runtime/mbitmap.go:911 + 0xa30 fp = 0xc02243c388 sp = 0xc02243c380 pc = 0x1016cd0 runtime.mallocgc (0x60, 0x1486e) /usr/local/Cellar/go/1.11.1/libexec/src/runtime/malloc.go:933 + 0x540 fp = 0xc02243c428 sp = 0xc02243c388 pc = 0x100d4f0 runtime.newobject (0x1486e60, 0x0) /usr/local/Cellar/go/1.11.1/libexec/src/runtime/malloc.go:1032 + 0x38 fp = 0xc02243c458 sp = 0xc02243c428 pc = 0x100db28 рефлексируйте.mapiterinit (0x14206a0, 0xc0000x8) 030x0000d8

1 Ответ

0 голосов
/ 07 ноября 2018

Сначала нужно указать encoding/json, чтобы пропустить родительское поле, это можно сделать с помощью тега json:"-".

Затем во время демаршалинга, после того как вы загрузили все дочерние элементы родителя, вы зациклили дочерние элементы и установили их родительский элемент, вы можете сделать это как часть процесса unamrshaling, реализовав интерфейс json.Unmarshaler .

type Mcloud struct {
    Projects map[string]*Project `json:"Projects"`
    Workdir  string
}

type Project struct {
    Name     string
    Networks map[string]Network
    Parent   *Mcloud `json:"-"` // ignore on un/marshal
    TFC      TFConf
}

func (m *Mcloud) UnmarshalJSON(data []byte) error {
    type tmp Mcloud
    if err := json.Unmarshal(data, (*tmp)(m)); err != nil {
        return err
    }

    // set Parent of all projects
    for _, p := range m.Projects {
        p.Parent = m
    }
    return nil
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...