Home > Mobile >  Rust: why can't I pattern match a mut String Option inside a loop?
Rust: why can't I pattern match a mut String Option inside a loop?

Time:05-30

I have this code here, where I try to extract some text based on a delimiter:

    //not working
    let mut text: Option<String> = None;
    for d in DELIMITERS {
        let split_res = full_text.split_once(d);
        if let Some((_, t0)) = split_res {
            let t = t0.to_string();
            match text {
                None => text = Some(t),
                Some(t2) => if t.len() < t2.len() {
                    text = Some(t); 
                }
            }
        }
    }

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8e4e0e8d7b2271b8f8ebd126896236ea

But I get these errors from the compiler

^^ value moved here, in previous iteration of loop

note: these 2 reinitializations might get skipped

What's going on here?

Why can't I pattern match on text? Is the problem that my text variable gets consumed? I can't really understand where and how?

Changing the code to use as_ref() on text fixes the error but I don't understand why this is necessary:

    //working
    let mut text: Option<String> = None;
    for d in DELIMITERS {
        let split_res = full_text.split_once(d);
        if let Some((_, t0)) = split_res {
            let t = t0.to_string();
            match text.as_ref() {
                None => text = Some(t),
                Some(t2) => if t.len() < t2.len() {
                    text = Some(t); 
                }
            }
        }
    }

CodePudding user response:

If you do not use as_ref, you are moving the object hence consuming it, so it is not available in the next iteration.

You can also match a reference:

match &text {}

Playground

Or you can take the inner value, leaving a None behind, that way you do not drop it. And since you re-assignate it afterwards keeps the same functionality:


const DELIMITERS: [&'static str; 2] = [
    "example",
    "not-found",
];

fn main() {
    let full_text = String::from("This is an example test");
    let mut text: Option<String> = None;
    for d in DELIMITERS {
        let split_res = full_text.split_once(d);
        if let Some((_, t0)) = split_res {
            let t = t0.to_string();
            match text.take() {
                None => text = Some(t),
                Some(t2) => if t.len() < t2.len() {
                    text = Some(t); 
                }
            }
        }
    }
    if let Some(t) = text {
        println!("{}", t);
    }
}

Playground

  • Related