Почему Cell in Rust может использоваться только для типов Copy, а не для клонирования?
Документация стандартной библиотеки Rust утверждает, что Cell
может использоваться только для типов Copy
и что во всех остальных случаях следует использовать RefCell
, но не объясняет, почему именно.
Изучив документацию и код как Cell
, так и RefCell
, единственной точкой, которая кажется важной, является функция get
Cell
. Если значение является типом Copy
, то можно просто вернуть такую копию. Но почему клон недостаточно хорош?
Можно непосредственно реализовать функцию set
поверх RefCell
:
fn set<T>(r: &RefCell<T>, v: T) {
*r.borrow_mut() = v
}
Это работает только до тех пор, пока никто другой не держит ссылку на значение. Но если значение может быть клонировано, можно просто сделать это:
fn get<T: Clone>(r: &RefCell<T>) -> T {
r.borrow().clone()
}
Наличие типа Cell
, работающего с типами Clone
, позволит избежать накладных расходов на проверку времени выполнения. Я что-то пропустил здесь?
Ответы
Ответ 1
Это необоснованно. Комментарий ДК. находится на правильном пути, но вам даже не нужна паника, чтобы вызвать хаос. Одним из проблемных сценариев является следующее:
- Ячейки (вместе с
Option
) позволяют создавать циклы, т.е. самореферентные типы
- Реализация
Clone
получает ссылку &self
- При наличии цикла реализация
Clone
может, таким образом, получить доступ к клеточке, которая клонируется
- Поэтому клонируемый объект может перезаписывать себя, в то время как он имеет обычный заимствование для себя (а именно
&self
)
- Переписывание во время заимствования является необоснованным, поскольку оно допускает произвольное произвольное наказание и другое плохое поведение. Например, предположим, что поле
Result<T, E>
, изначально Ok(T)
, возьмите ссылку на T
внутри и перезапишите Result
с помощью Err(R)
. Затем &T
внезапно ссылается на значение E
.
Кредит для этого примера относится к Huon Wilson, см. thread.rust-lang.org Почему Cell требует Copy вместо Clone?. Его рецензия касается более структурных причин ограничений и включает полный пример кода.
Ответ 2
Вот мое мнение, но я не могу привязать его прямо к реальной причине, что такое ограничение существует.
Я думаю о копии как "дешевой" (например, копировании нескольких бит), а клон - "дорогой" (например, вызов функции или изменение данных). Если бы такая ячейка использовала Clone
, ей было бы поручено дублировать базовое значение при каждом использовании (cell.get()
). Например, использование CloneCell<Vec<T>>
будет означать, что для каждого cell.get()
требуется вызвать вызов распределителя памяти. Это не очень хорошая идея.
Ограничение типов Copy
, таким образом, потенциально может помочь людям не стрелять в ногу.