環境
- rust 1.58.1
やりたかったこと
Vec<Result<Hoge>>型があったとして(Hogeは適当なstruct)、Hogeだけ取得したかった。
以下ではHogeはStringにしています。
// こんなデータがあるとして
let v: Vec<String> = vec!["1".to_string(),"2".to_string(),"3".to_string()];
let string_results = v.into_iter()
.map(|x| Ok(x))
.collect::<Vec<Result<String, String>>>();
// Vec<Result<String, String>> からVec<String>をつくりたい!
ハマったこと
let v: Vec<String> = vec!["1".to_string(),"2".to_string(),"3".to_string()];
let string_results = v.into_iter()
.map(|x| Ok(x))
.collect::<Vec<Result<String, String>>>();
// これでいけんじゃね?
let inners: Vec<String> = string_results.iter().filter_map(|x| x.ok()).collect();
↓
cannot move out of `*x` which is behind a shared reference
move occurs because `*x` has type `Result<String, String>`, which does not implement the `Copy` traitrustcE0507
main.rs(25, 61): consider borrowing the `Result`'s content: `.as_ref()`
というエラーになってしまってうまくいかない。ok()はselfを消費するからっぽい。
解決方法1
所有権を使ってよいなら、into_iter()を使えば大丈夫
// Vec<Result<String, String>> からVec<String>をつくりたい!
// iter -> into_iterに変更
let inners: Vec<String> = string_results.into_iter().filter_map(|x| x.ok()).collect();
ただし、これだとstring_resultsの所有権が消費されてしまうため、string_resultsをもう使えなくなってしまう。
解決方法2
所有権を消費せずにこれを行うには、上にメッセージででてたas_ref()を使う
// Vec<Result<String, String>> からVec<String>をつくりたい!
// as_ref().ok()にして、中身を参照型で取り出す
let inners: Vec<String> = string_results.iter().filter_map(|x| x.as_ref().ok())
// .map(|x| x.clone()) // 実態にするのは別mapで
.cloned() // 2022-03-06: benki様からご教示いただき、clonedに修正しました。
.collect();
備考
- なんかもっときれいな方法とかスッキリやる方法あるのではないかという気がする。。