Рассмотрим следующий код:
fn print_or(opt: Option<()>, tail: Vec<i32>) -> Vec<i32> {
opt.map_or(tail, |_| {
println!("{:?}", tail);
tail
})
}
В сообщении об ошибке говорится, что:
error[E0382]: use of moved value: `tail`
--> src/lib.rs:2:22
|
1 | fn print_or(opt: Option<()>, tail: Vec<i32>) -> Vec<i32> {
| ---- move occurs because `tail` has type `Vec<i32>`, which does not implement the `Copy` trait
2 | opt.map_or(tail, |_| {
| ---- ^^^ value used here after move
| |
| value moved here
3 | println!("{:?}", tail);
4 | tail
| ---- use occurs due to use in closure
|
help: consider cloning the value if the performance cost is acceptable
|
2 | opt.map_or(tail.clone(), |_| {
| ++++++++
И это понятно, поскольку я использую здесь собственный шрифт Vec<i32>
. Но проблема в том, что совершенно очевидно, что его нельзя использовать после перемещения, поскольку Option
не может быть Some
и None
одновременно. Есть ли способ решить проблему без clone
или Rc
?
Вы можете встроить Option::map_or
, чтобы помочь компилятору понять, что он должен перемещаться tail
в каждую ветку условно.
fn print_or(opt: Option<()>, tail: Vec<i32>) -> Vec<i32> {
match opt {
Some(()) => {
println!("{:?}", tail);
tail
}
None => tail,
}
}
В Rust на самом деле нет способа сказать, что будет использоваться только один аргумент функции, но он знает, что будет выполняться только одна ветвь оператора потока управления, поэтому вы можете использовать match
:
match opt {
None => tail,
Some(()) => {
println!("{:?}", tail);
tail
}
}
Аналогично вы можете использовать if let
:
if let Some(()) = opt {
println!("{:?}", tail);
tail
} else {
tail
}
И в этом случае вы можете просто проверить, является ли opt
Some
, поскольку обе ветви заканчиваются одним и тем же:
if opt.is_some() {
println!("{:?}", tail);
}
tail