я знаю, что использование RefCell
требует затрат во время выполнения, а также я узнал, что можно избежать его использования, заменив его на Cell<Option<T>>
или Cell<T>(T impl Default)
и используя take
или replace
, чтобы получить экземпляр, изменить его, а затем вернуть обратно.
но есть и некоторые затраты: мне нужно обернуть T с помощью Some
и использовать if let Some(t)
и .set(Some(t))
, чтобы получить и положить его обратно. я не знаю, стоит ли заменять RefCell на Cell<Option>
Если вам нужен более подробный обзор производительности, вам следует показать конкретные примеры кода. То, что вы описали, оставляет некоторую двусмысленность, поэтому я не могу дать более однозначного ответа, чем общие советы, приведенные выше.
Суть: RefCell<T>
более гибок и прост в использовании, имеет меньше ошибок. В большинстве ситуаций он будет превосходить или работать не хуже Cell<Option<T>>
. Его следует использовать до тех пор, пока не будет доказано, что небольшой размер накладных расходов является проблемой (по результатам теста!)
RefCell<T>
Cell<Option<T>>
Cell<T: Default>
доступ с
общий: borrow()
borrow_mut()
общий: невозможно take()
общий: невозможно (только первый take
получает реальное значение и только последний replace
вступает в силу take()
доступ к производительности
должен проверить, доступно ли значение, и обновить целое число
необходимо проверить, доступно ли значение, и заменить Some(t)
на None
необходимо использовать T::default()
для замены взятого значения, что может быть дорогостоящим
доступ проверен
всегда
всегда (Option
— это None
, когда значение извлекается)
никогда, в результате две параллельные ветки могут иметь значение, и обновления любой из ветвей могут быть пропущены.
одновременный доступ
может раздавать несколько общих ссылок одновременно
невозможно
невозможно (второй доступ получит только T::default()
и не сможет узнать)
высвобождение значения
автоматически, когда Ref
/RefMut
отбрасывается, когда он выходит за пределы области видимости, или вручную, drop
пингуя его
надо не забыть использовать replace
надо не забыть использовать replace
производительность выпуска ценности
уменьшить целое число
замените None
на Some(t)
T::drop
что может быть дорого
размер
всегда дополнительный указатель на всю ширину, который отслеживает, сколько Ref
/RefMut
находится в обращении
обычно требуется количество байтов, равное выравниванию T
дополнительно для дискриминанта, или вообще никаких дополнительных затрат на размер, если T
имеет нишу, которую Option
можно использовать
нет накладных расходов на размер
Подводя итог, можно сказать, что да, вы можете избежать использования RefCell
, но вы все равно понесете затраты во время выполнения.
Вряд ли она будет даже больше, чем небольшая стоимость RefCell
. Единственное, на чем иногда можно сэкономить, — это накладные расходы на размер в одну ширину указателя, который отслеживает количество Ref[Mut]
в обращении.
Короткий ответ. Нет. Просто используйте
RefCell
. Он ясно показывает ваше намерение реализовать проверку заимствований и перенести ее в среду выполнения, а также имеет несколько более удобных API.Cell
был создан для чего-то другого. Таким образом, хотя вы можете использовать его так, как вы описали, это будет неэргономично, сбивает с толку других и, вероятно, приведет к большему потреблению памяти.