What is the scope?(Borrowed value does not live long enough)

Hello, I am trying to solve the advent of code series using Rust.
Unfortunately I got an error that I could not understand its cause. Added my code and error below. I have experience with other programming languages like Python and C#, but Rust is in another league :smiley:
Shouldn't "cap" be available for the scope of the for loop in which is declared? Could you please explain me what I am doing wrong.

use std::collections::HashMap;
use std::io::{BufRead, BufReader};
use std::{fs::File, path::Path};
use regex::Regex;


fn main() {

    let max_color_allowed_values: HashMap<&str, i32> = HashMap::from([
        ("red",12),
        ("green", 13),
        ("blue", 14),
    ]);

    let cubes_regex = Regex::new(r"(\d+)\s+(\w+)").unwrap();
    let game_regex = Regex::new(r"(\d+)").unwrap();

    let mut total_value_part_1 = 0;
    // let mut total_value_part_2 = 0;


    let path = Path::new("input/input.txt");
    let display = path.display();

    // println!("{}", display);

    let file = match File::open(path) {
        Ok(file) => file,
        Err(why) => panic!("couldn't open {}: {}", display, why)
    };

    let reader = BufReader::new(file);

    for line in reader.lines(){
        let input_line = match line{
            Ok(line) => line,
            Err(why) => panic!("couldn't read line {}", why)
        };
        let split_parts: Vec<&str> = input_line.split(":").collect();

        let game_substr = split_parts[0];
        let cubes_substr = split_parts[1];

        // println!("Game substr: {}", game_substr);
        // println!("Cubes substr: {}", cubes_substr);

        let mut maximum_value_color = HashMap::from([
            ("red",0),
            ("green", 0),
            ("blue", 0),
        ]);

        let cubes_rounds: Vec<&str> = cubes_substr.split(";").collect();

        let mut valid_game = true;

        for round in cubes_rounds{
            for cap in cubes_regex.captures_iter(round){
                let number_of_cubes: i32 = cap[1].parse().unwrap();
                let color = &cap[2];
                
                let max_defined_value = *max_color_allowed_values.get(color).unwrap();


                if max_defined_value < number_of_cubes{
                    valid_game = false;
                    // should we continue looping values for this game if valid_game is false?
                    // need to let this flow for part 2
                }


                // let max_current_value = maximum_value_color.entry(color).or_insert(0);
                let max_current_value = maximum_value_color.get(color).unwrap();

                if number_of_cubes > *max_current_value{
                    maximum_value_color.insert(color, number_of_cubes);
                }
                    

            }
        }

        if valid_game == true{
            let mut game_value: isize = 0;
            for cap_group in game_regex.captures_iter(game_substr){
                // println!("Captured group {}", cap_group.get(0).unwrap().as_str());
                game_value = cap_group.get(0).unwrap().as_str().parse().unwrap();
            }
            total_value_part_1 += game_value;
        }

    }
    println!("Total value for all valid games in part 1: {}", total_value_part_1);

}
error[E0597]: `cap` does not live long enough
  --> src/main.rs:60:30
   |
58 |             for cap in cubes_regex.captures_iter(round){
   |                 --- binding `cap` declared here
59 |                 let number_of_cubes: i32 = cap[1].parse().unwrap();
60 |                 let color = &cap[2];
   |                              ^^^ borrowed value does not live long enough
...
73 |                 let max_current_value = maximum_value_color.get(color).unwrap();
   |                                         ------------------- borrow later used here
...
80 |             }
   |             - `cap` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.```

cap lives for one iteration of the loop, not the whole loop. But either way, it definitely does not live as long as maximum_value_color is live. When you insert the color you get from cap into maximum_value_color, try inserting an owned color value instead of a reference, i.e. by cloning the color. Or use Captures::get instead of indexing as the former allows you to get a reference with the lifetime of the underlying haystack, independent of how long the capture lives:

- let color = &cap[2];
+ let color = cap.get(2).unwrap().as_str();
2 Likes

My understanding is that I will get a new cap for each match of the regex.
Tried inserting a cloned value of color but without any success.

maximum_value_color.insert(color.clone(), number_of_cubes);
error[E0597]: `cap` does not live long enough
  --> src/main.rs:60:30
   |
58 |             for cap in cubes_regex.captures_iter(round){
   |                 --- binding `cap` declared here
59 |                 let number_of_cubes: i32 = cap[1].parse().unwrap();
60 |                 let color = &cap[2];
   |                              ^^^ borrowed value does not live long enough
...
73 |                 let max_current_value = maximum_value_color.get(color).unwrap();
   |                                         ------------------- borrow later used here
...
80 |             }
   |             - `cap` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.

Changing it to use Captures::get did the trick. Thanks a lot!
Could you please explain/point me what was the cause of the problem? Why would my reference to cap would outlive the cap itself?

Here an example using String instead of &str and here an example of using Captures::get instead of indexing into cap.

Its because you can't define Index in a way that the value returned by the indexing operation may outlive the indexed object (it's missing a generic lifetime parameter for that and uses the elided lifetime of &self instead). See here.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.