2016-07-06 2 views
6

У меня есть перечисление в Rust, у которого есть одно значение, которое принимает String. Это может быть продемонстрировано с помощью этого простого примера:Как реализовать Clone/Copy для перечисления, содержащего String?

#[derive(Clone, Copy)] 
enum Simple { 
    Error(String), 
    Okay, 
    Foo([u32; 5]), 
} 

fn main() { 
    let x = Simple::Error(String::from("blah")); 
    let y = x.clone(); 
} 

Значение перечисления Foo выше, представляет собой около 10 других перечислений, которые я использую, которые принимают Copyable типы или массивы из них. Компилятор, кажется, не жалуются на них, только Error(String), который вызывает это:

error: the trait `Copy` may not be implemented for this type; variant `Error` does not implement `Copy` [E0205] 
#[derive(Clone, Copy)] 
       ^~~~ 

note: in this expansion of #[derive_Copy] (defined in src\main.rs) 
help: run `rustc --explain E0205` to see a detailed explanation 

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

ответ

16

Copy обозначает типы, для которых создание побитовой копии создает действительный экземпляр без аннулирования исходного экземпляра. Это неверно для String, потому что String содержит указатель на строковые данные в куче и предполагает, что он обладает уникальной собственностью этих данных, и, таким образом, когда вы отбрасываете String, он освобождает данные от кучи, и если вы сделали побитовая копия String, то оба экземпляра попытаются освободить один и тот же блок памяти, который является неопределенным поведением. Поскольку String не реализует Copy, , ваш enum не может реализовать Copy либо, так как компилятор устанавливает, что типы Copy состоят только из членов данных Copy.

Clone просто предоставляет стандартный метод clone, и каждый разработчик может решить, как его реализовать. String делает. Clone, поэтому вы можете положить #[derive(Clone)] на ваш enum.

+0

Я должен добавить, что я не понимаю, почему String не может реализовать принцип копирования в принципе или на практике - объекты QString в QT могут быть скопированы, и они совместно используют и поддерживают внутренний буфер. Если копия делает что-то изменчивое, буфер сначала клонируется, поэтому в других экземплярах сохраняется ссылка на исходный буфер. В QT по-прежнему лучше переходить по ссылке, чтобы избежать атомного пересчета, но копия в любом случае эффективна. – locka

+0

@locka потому что * 'Copy' обозначает типы, для которых создание побитовой копии создает действительный экземпляр *. Копирование бит такой строки не может увеличивать атомный счетчик, потому что это не будет копировать. Вы можете выбрать, какие гарантии вам понадобятся. Вы можете [передать права собственности] (http://doc.rust-lang.org/std/rc/struct.Rc.html), [владеть акциями через потоки] (http://doc.rust-lang.org/std /sync/struct.Arc.html), реализовать [clone on write] (http://doc.rust-lang.org/std/borrow/enum.Cow.html) и т. д. Это не подходит для систем язык, чтобы принять это решение (и обременять ваш код) для вас. – Shepmaster

Смежные вопросы