Первый : в Rust нет неявных дорогостоящих копий, в отличие, например, от C ++. В то время как в C ++ действием по умолчанию является «глубокое копирование» (через конструктор копирования или подобное), действие по умолчанию в Rust движется. Перемещение - это мелкая копия, которая (а) обычно очень мала и дешева и (б) может быть удалена оптимизатором в большинстве случаев. Чтобы получить глубокие клоны в Rust, вы должны вручную использовать .clone()
. Если вы этого не сделаете, , вам обычно не нужно беспокоиться об этом
Секунда : при сопоставлении с перечислением рассматривается только дискриминант этого перечисления (если вы не связываете поля перечисления, см. Ниже). Это тег или метаданные, которые указывают, какой вариант перечисления хранится в значении. Этот тег крошечный: он вписывается в 8 бит почти во всех случаях (перечисления с более чем 256 вариантами встречаются редко). Так что вам не нужно беспокоиться об этом. И в вашем случае у нас есть C-подобные перечисления без каких-либо полей. Таким образом, enum хранит только тег и, следовательно, тоже крошечный.
Так что насчет полей enum, которые могут быть дорогостоящими для копирования? Как это:
enum SomeEnum {
SomeEntry(String),
AnotherEntry,
}
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match *boxed_value {
SomeEnum::SomeEntry(s) => drop::<String>(s), // make sure we own the string
SomeEnum::AnotherEntry => {},
}
Так что в этом случае один вариант хранит String
. Поскольку глубокое копирование строки довольно дорого, Rust не будет делать это неявно. В матче мы пытаемся сбросить s
и утверждать, что это String
. Это означает, что мы (то есть: тело совпадающей руки) владеем строкой. Таким образом, когда спичечное устройство владеет им, но мы не клонировали его, это означает, что внешняя функция больше не может им владеть. И на самом деле, если вы попытаетесь использовать boxed_value
после совпадения, вы получите ошибки перемещения от компилятора. Опять же, либо вы получите ошибку компилятора, либо автоматически не произойдет ничего плохого.
Кроме того, вы можете написать SomeEnum::SomeEntry(ref s)
в match
. В этом случае строка связана ссылкой s
(поэтому вызов drop()
больше не будет работать). В этом случае мы никогда не переходим от boxed_value
. Это то, что я называю «отложенным перемещением», но я не уверен, что это официальный термин для этого. Но это просто означает: при сопоставлении с образцом входное значение вообще не перемещается, пока из него не сместится привязка в шаблоне.
И, наконец, посмотрите этот код и сгенерированную сборку . Сборка оптимальна. Итак, еще раз: хотя вы можете беспокоиться о случайных клонах, когда вы пришли из мира C ++, на самом деле это не то, о чем вам нужно беспокоиться в Rust.