Разрушающее сопоставление с образцом

В Rust используется разрушающее сопоставление с образцом, что в купе с моделью памяти Rust, иногда, дает очень занятные эффекты. Для примера возьмем структуру MyStruct и создадим две переменные типа Option в которых будет лежать наша структура, в одном случае 1 в виде стекового объекта, а во втором в виде уникального указателя 2.

struct MyStruct {
    val: int
}
let stack_data = Some(MyStruct{val:42});   // (1)
let own_data = Some(~MyStruct{val:42});    // (2)


И теперь попробуем применить сопоставление с образцом, но не один раз, как это обычно делается, а дважды. Сценарий выглядит не совсем обычно, но это не более чем выжимка из реального кода.

match a_data {                                             // (1)
    Some(data) => { println!("We have data {:?}", data);}
    None => { println!("We don't have data");}
}
match a_data {                                             // (2)
    Some(data) => { println!("We have data {:?}", data);}
    None => { println!("We don't have data");}
}

Что бы не приводить один и тот же пример дважды, переменная a_data 1 служит просто для иллюстрации, и в реальном коде вместо нее используется либо stack_data либо own_data из примера выше.

Данный код при использовании stack_data соберется и дважды выведет на экран “We have data MyStruct{val: 42}”, а вот на сборке с использованием own_data компилятор выдаст сообщение об ошибке следующего содержания на второе сопоставление с образцом 2:

destructive_match.rs:30:11: 30:21 error: use of partially moved value: `local_data`
destructive_match.rs:30     match local_data {
                                  ^~~~~~~~~~
destructive_match.rs:27:14: 27:18 note: `local_data#0` moved here because it has type `~MyStruct`, which is moved by default (use `ref` to override)
destructive_match.rs:27         Some(data) => { println!("We have data {:?}", data);}
                                     ^~~~
error: aborting due to previous error

Два этих случая хоть и крайне похожи, но имеют “ньюансик”. Стековые объекты в Rust копируются, как следствие в обоих сопоставлениях с образцом 1,2 подвергается разрушению не объкт stack_data, а его копия. В то время как уникальные указатели реализуют семантику владения в следствии чего первое 1 же разрушающее преобразование захватывает объект MyStruct и дальнейшая работа 2 с own_data становится не возможной.

Что делать и как быть? Например, попросить компилятор не передвигать объект MyStruct, а получить ссылку на него:

match local_data {
    Some(ref data) => { println!("We have data {:?}", data);}
    None => { println!("We don't have data");}
}

Leave a Reply