2

As a rust newbie I have a problem finding an element in a vector of Option using the "find" function:

#[derive(Debug)]
struct MyStruct {
    name: Option<String>,
    data: Option<String>
}

fn main() {
    let my_vec=vec![
        MyStruct{
            name:Some(String::from("name1")),
            data:Some(String::from("data1"))
        },
        MyStruct{
            name:Some(String::from("name2")),
            data:Some(String::from("data2"))
        }
    ];
    let search_string = String::from("name2");
    let found_record=my_vec.iter().find(|s| s.name == Some(search_string));
    println!("{:?}", found_record);
}

This code does not compile because of the comparison s.name == Some(search_string) because of a missing Copy trait. What would be the correct way for the "find" expression?

asmmo
  • 6,922
  • 1
  • 11
  • 25
  • 1
    Your question can be answered by [Cannot move out of captured outer variable in an `Fn` closure](https://stackoverflow.com/questions/33662098/cannot-move-out-of-captured-outer-variable-in-an-fn-closure) and [Converting from Option to Option<&str>](https://stackoverflow.com/questions/31233938/converting-from-optionstring-to-optionstr) – Ibraheem Ahmed Feb 21 '21 at 19:01
  • `my_vec.iter().find(|s| s.name.as_deref() == Some("name2"))` – Ibraheem Ahmed Feb 21 '21 at 19:01

2 Answers2

2

One option is to convert both your search_string and struct field to Option<&str> for comparison:

let found_record = my_vec.iter().find(
  |s| s.name.as_deref() == Some(search_string.as_ref()));

playground

Psidom
  • 209,562
  • 33
  • 339
  • 356
  • Thank you very much. Is there is difference if I use `Some(&search_string)` instead of the suggested `Some(search_string.as_ref())`? Both versions compile and return the correct answer. – Udo Eisenbarth Feb 21 '21 at 19:17
  • They should be equivalent for your use case here. Just to notice that `Some(&search_string)` returns `Option<&String>` while the latter returns `Option<&str>`, they are different but both should give the correct answer. – Psidom Feb 21 '21 at 19:22
1

The Error cause

Note that you are constructing an Option by using Some() inside the closure by moving the String.


Some solutions

  1. You can avoid that moving and make the closure capture by immutable reference by constructing the Option before it, as follows
let search_string = Some(String::from("name2"));
let found_record=my_vec.iter().find( |s| s.name == search_string);

  1. Or enter inside the Option, as follows
let search_string = String::from("name2");
let found_record=my_vec.iter().find( 
    |s| match &s.name{Some(name)=> name, _ => return false,} == &search_string
);


I don't prefer the approach

let found_record = my_vec.iter().find(
  |s| s.name.as_deref() == Some(search_string.as_ref()));

because it makes a new Some() every iteration unless if there is an optimization by the compiler.

asmmo
  • 6,922
  • 1
  • 11
  • 25
  • @UdoEisenbarth If u mean in the 2nd case, Nope. Note that the result of the first match arm will be of type `&String` because you match over a `&Option`, not an `Option` – asmmo Feb 21 '21 at 19:27