LINUX.ORG.RU

Десериализация дерева нод из JSON

 


0

3

Есть следующая структура:

type I3Node struct {
	Id                   int32
	Name                 string
	Type                 string
 	...
	Floating_Nodes       []I3Node
	Nodes                []I3Node
}

Она заполняется десериализацией из json функцией json.Unmarshal(json_reply, &root)
Хочу добавить в структуру поле Parent *I3Node, указывающее на родительскую ноду.
Подскажите, как проще всего это сделать?
Пока рассматриваю вариант обхода дерева сразу после десериализации и ручного указания нодам ссылки на родительскую ноду.



Последнее исправление: cetjs2 (всего исправлений: 2)

Если я правильно понял постановку задачи, то как-то так:

type I3Node struct {
        Id     int
        Name   string
        Type   string
        Nodes  []I3Node
        Parent *I3Node `json:"-"`
}

func Decode(r io.Reader) (v I3Node) {
        json.NewDecoder(r).Decode(&v)
        for i, n := range v.Nodes {
                n.Parent = &v
                v.Nodes[i] = n
        }
        return
}

beastie ★★★★★
()

Сделал так:

func (self *I3Node) SetParent(parent *I3Node) {

	self.Parent = parent

	if self.Parent != nil {
		fmt.Println("My ID", self.Id, "Parent ID", self.Parent.Id)
	} else {
		fmt.Println("Root node", self.Id)
	}

	for _, node := range self.Nodes {
		node.SetParent(self)
	}
	for _, node := range self.Floating_Nodes {
		node.SetParent(self)
	}
}

Вызываю:
func (self *IPCSocket) GetTree() (root I3Node, err error) {
	...
	err = json.Unmarshal(json_reply, &root)
	root.SetParent(nil)
	fmt.Printf("%#v\n", root)
	...
}

Получаю такой отладочный вывод:
	...
	My ID 36316976 Parent ID 36317344
	My ID 36317344 Parent ID 36316608
	My ID 36316608 Parent ID 35145920
	My ID 35145920 Parent ID 35144864
	My ID 35153056 Parent ID 35144864
	My ID 35144864 Parent ID 35139792
	Root node 35139792

	Далее вывод fmt.Printf("%#v\n", root),
	в котором видно, что во всех нодах
        Parent == nil (Parent:(*i3ipc.I3Node)(nil))

Вроде же по ссылке передаю структуру в метод, почему тогда не видно изменений?

Smola
() автор топика
Ответ на: комментарий от beastie

Не совсем понял, будет ли это работать при любой глубине дерева? Я хочу, чтобы с листа любого уровня вложености, можно было двигаться вверх по дереву, типа leaf.Parent.Parent.Parent.Parent.Parent. Прости если криво описал задачу.

Smola
() автор топика
Последнее исправление: Smola (всего исправлений: 1)
Ответ на: комментарий от feofan

https://play.golang.org/p/x39mweifKB

Тестовый JSON в читаемом виде:

{
  "id": 1,
  "name": "root",
  "nodes": [
    {
      "id": 2,
      "name": "first",
      "nodes": [
      
      ]
    },
    {
      "id": 3,
      "name": "second",
      "nodes": [
        {
          "id": 4,
          "name": "third",
          "nodes": []
        },
        {
          "id": 5,
          "name": "fourth",
          "nodes": []
        },
      ]
    }
  ]
}

Вывод:
Root node 1
My ID 2 Parent ID 1
My ID 3 Parent ID 1
My ID 4 Parent ID 3
My ID 5 Parent ID 3
main.I3Node{Id:1, Name:"root", Floating_Nodes:[]main.I3Node(nil), Nodes:[]main.I3Node{main.I3Node{Id:2, Name:"first", Floating_Nodes:[]main.I3Node(nil), Nodes:[]main.I3Node{}, Parent:(*main.I3Node)(nil)}, main.I3Node{Id:3, Name:"second", Floating_Nodes:[]main.I3Node(nil), Nodes:[]main.I3Node{main.I3Node{Id:4, Name:"third", Floating_Nodes:[]main.I3Node(nil), Nodes:[]main.I3Node{}, Parent:(*main.I3Node)(nil)}, main.I3Node{Id:5, Name:"fourth", Floating_Nodes:[]main.I3Node(nil), Nodes:[]main.I3Node{}, Parent:(*main.I3Node)(nil)}}, Parent:(*main.I3Node)(nil)}}, Parent:(*main.I3Node)(nil)}

Smola
() автор топика
Ответ на: комментарий от Smola

Как видно отсюда https://play.golang.org/p/MtjMBNP8eC судя по всему, тут может быть виновато перевыделение памяти. Похоже на баг рантайма. В качестве воркэраунда могу посоветовать возвращать результат явно (использовать как append).

feofan ★★★★★
()
Ответ на: комментарий от feofan

Спасибо, я сегодня весь день потратил пытаясь выяснить в чем проблема. Не ожидал, что в первый же день изучения Го наткнуся на баг в рантайме, лол.

Smola
() автор топика
Ответ на: комментарий от Smola

На самом деле надо внимательно изучить спецификацию языка, возможно я ошибаюсь и это корректное, задокументированное поведение. Хотя на первый взгляд кажется, что таки нет.

feofan ★★★★★
()
Ответ на: комментарий от Smola

В самом деле, я был неправ:

The reason for this is that range copies the values from the slice you're iterating over. The specification about range says

Ты изменял копии дочерних нод. А мне нужно больше спать.

feofan ★★★★★
()
Последнее исправление: feofan (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.