Is there a way to free the binding before it goes out of scope?

I am trying to parse a file using regular expressions:

if let Some(m) = section_header_pattern.captures(&line).and_then(|c| c.get(1)) { is_in_right_section = m.as_str().eq(section_name); line.clear(); continue; } 

... but the compiler complains because the RegEx captures() method has a borrowing that withstands the lifetime of the match:

 error[E0502]: cannot borrow `line` as mutable because it is also borrowed as immutable --> src/main.rs:58:13 | 56 | if let Some(m) = section_header_pattern.captures(&line).and_then(|c| c.get(1)) { | ---- immutable borrow occurs here ... 58 | line.clear(); | ^^^^ mutable borrow occurs here 59 | continue; 60 | } | - immutable borrow ends here 

By the time I get to line.clear(); I finished with Match and would like to clear the buffer and go to the next line in the file without further processing. Is there a good / clean / elegant / idiomatic solution, or do I just need to bite the bullet and enter the next "if" block?

+8
rust borrow-checker
source share
1 answer

Short answer: None.

I finished with Match

You may be, but the compiler does not know this. In particular, life spans are associated with the lexical area in which they are defined. The magic function you are looking for is called non-electric life spans . It does not exist now, but many people would like it.

As an example:

 fn main() { let mut s = String::from("hello"); let matched = &s[..]; println!("{}", matched); s.clear(); println!("{}", s); } 

The programmer may say that we are done with matched after printing it, but the compiler says that the debt lasts until closing } . The fix is ​​to enter the scope:

 fn main() { let mut s = String::from("hello"); { let matched = &s[..]; println!("{}", matched); } s.clear(); println!("{}", s); } 

Your business is more insidious, since the decision to clear the line is intertwined with the value of borrowing the line itself. Something like this will be my first place to achieve:

 fn main() { let mut s = String::from("hello"); let do_clear; { let matched = &s[..]; println!("{}", matched); do_clear = matched.contains("ll"); } if do_clear { s.clear(); } println!("{}", s); } 

However, your specific case can be converted to avoid multiple if / if let :

 let is_in_right_section = section_header_pattern.captures(&line) .and_then(|c| c.get(1)) .map_or(false, |m| m.as_str() == section_name); if is_in_right_section { line.clear(); continue; } 

That would not look too bad if you introduce a new type and / or method. As a bonus, there is a place for Regex :

 struct Section(Regex); impl Section { fn is(&self, s: &str, section: &str) -> bool { self.0 .captures(s) .and_then(|c| c.get(1)) .map_or(false, |m| m.as_str() == section) } } // ---- if section.is(&line, section_name) { line.clear(); continue; } 
+7
source share

All Articles