Я потратил некоторое время на разработку нового проекта на Rust.
У меня возникла проблема с пониманием того, правильно ли я использую Cell. Это моя текущая проблема, в общем.
Мне нужен доступ к структуре World, которая владеет некоторыми ресурсами. В частности мне нужны (mut) ссылки на ресурсы. Проблема возникает, когда мне нужен изменяемый доступ к ресурсу (требующий &mut World) и немутируемая ссылка (требующая &World). Я не могу собрать такие ссылки вместе, так как это нарушит правила ссылок Rust.
Я хотел бы решить эту проблему с помощью Cell. У меня есть этот код в моем проекте:
fn take_world(&self, func: impl FnOnce(World) -> World) {
let state = self.state_ref();
let world = state.world
.take();
let world = func(world);
state.world
.replace(world);
}
Это должно позволить мне взять мир из ячейки, сделать то, что мне нужно, с помощью FnOnce и автоматически заменить его.
Как вы думаете, это хороший подход? Можно ли это считать запахом кода?
Другие решения могут включать рефакторинг кода, но часть World/Resource взята из библиотеки, поэтому я ничего не могу с этим поделать.
Кроме того, «запах кода» субъективен. Если не хотите, чтобы ваш вопрос закрыли, поставьте объективную меру.
изменяемой ссылки недостаточно, поскольку для получения двух разных ресурсов потребуются две изменяемые ссылки на мир; это или я упускаю что-то очевидное.
Вы можете взять значение с изменяемой ссылкой, а затем взять общую ссылку (только если изменяемая ссылка стоит первой).
как я могу это сделать, если им обоим одновременно требуются изменяемая и неизменяемая ссылка на мир?
Они не могут быть действительно одновременно, одно должно быть раньше другого.
вот почему я подумал об использовании сотового телефона
Это не запах кода сам по себе.
Cell
предназначен для обеспечения внутренней изменчивости без затрат памяти, но он делает это, запрещая ссылочный доступ к своему содержимому, и его нельзя использовать в нескольких потоках. Таким образом, эффективно вы можете получить и установить значение в Cell
, только передав право собственности (или Copy
-ing). Так что это не только не запах кода, но и практически единственный способ обновить значение в Cell
на основе его предыдущего значения. Обертывание его в функцию — это просто естественное расширение. Существует даже метод .update(), который скоро будет стабилизирован, который примерно делает это за вас (хотя он полагается на Copy
вместо заполнения Default
).
Будет ли использование Cell
для манипулирования вашим World
запахом кода или нет, будет зависеть от остальной части вашего дизайна и отклонится от мнения. Вы отметили Bevy, который предоставляет множество способов работы с сущностями и компонентами, поэтому я чувствую, что, вероятно, есть способ сделать то, что вы хотите, без внутренней изменчивости, но это всего лишь предположения.
Cell
для этого не нужен — достаточно изменяемой ссылки.