Рекурсивное построение класса данных в Kotlin

#kotlin #recursion

#kotlin #рекурсия

Вопрос:

Я пытаюсь создать рекурсивный класс данных следующим образом:

 data class AttributeId (
  val name: String,
  val id: Int,
  val children: List<AttributeId>?
)
 

То, с чем я сейчас борюсь, — это создание класса данных путем итерации по исходному объекту.
Как мне рекурсивно построить этот объект?? Является ли класс данных здесь неправильным решением?

РЕДАКТИРОВАТЬ: еще немного информации об исходном объекте, из которого я хочу создать свой экземпляр класса данных

Исходный объект представляет собой поток Java, который по существу * имеет следующую форму:

 public Category(final String value,
                      final Integer id,
                      final List<Category> children) {
    this.value = value;
    this.id = id;
    this.children = children;
}
 

(Для краткости поля, о которых я не забочусь, были удалены из примера)

Я думаю, что мне нужно отобразить этот поток и вызвать рекурсивную функцию, чтобы создать класс данных AttributeID, но мои попытки, похоже, заканчиваются переполнением стека и большой путаницей!

Комментарии:

1. Зависит от того, как выглядит исходный объект.

2. Ваш конечный класс данных выглядит красиво — неизменяем. Если это ограничение не соответствует вашим потребностям при создании экземпляра, рассмотрите возможность использования шаблона builder. Вы можете ввести некоторый конструктор, в котором все структуры данных изменчивы, но в конце концов вы преобразуете все в эту неизменяемую структуру и возвращаете ее во внешний мир…

Ответ №1:

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

Конечно, есть некоторые ошибки. Например:

  • Если бы список был изменяемым или если бы его поле было изменяемым (т. Е. var Скорее, Чем val ), тогда вам пришлось бы проявить осторожность, потому что его хэш-код и c могли измениться.
  • И если цепочка ссылок может образовывать цикл (т. Е. Вы можете перейти по ссылкам и вернуться к исходному классу), это может быть очень опасно. (Например, вызов такого метода, как toString() or hashCode() , может либо застрять в бесконечном цикле, либо привести к сбою потока с помощью a StackOverflowError . Вы должны были бы предотвратить это, переопределив эти методы, чтобы предотвратить их повторное использование.) Но этого не могло бы произойти, если бы список и поле были неизменяемыми.

Однако ни одна из этих проблем не является специфичной для классов данных; обычный класс может страдать от тех же проблем (особенно, если вы переопределили методы, подобные toString() или hashCode() не заботясь об этом). Итак, независимо от того, делаете ли вы это классом данных, зависит от того, похож ли он на него: является ли его основной целью хранение данных и / или соответствуют ли автоматически сгенерированные методы тому, как вы хотите, чтобы они вели себя.

Как говорит Tenfour04, это зависит от того, из чего вы их создаете. Если он естественным образом формирует древовидную структуру, то это может быть хорошим представлением для него.

Очевидно, что вы не сможете создать родительский элемент перед любым из его дочерних элементов. (В частности, первый созданный вами экземпляр должен иметь null либо пустой список для its children .) Вероятно, это означало бы обход источника в последующем порядке. Остальное должно выпадать естественным образом из этого.