How to allocate a string before you know how big it needs to be

烂漫一生 提交于 2019-12-23 07:05:38

问题


I'm sure this is a beginners mistake. My code is:

...
let mut latest_date : Option<Date<Local>> = None;
let mut latest_datetime : Option<DateTime<Local>> = None;
let mut latest_activity : Option<&str> = None;

for wrapped_line in reader.lines() {
    let line = wrapped_line.unwrap();
    println!("line: {}", line);

    if date_re.is_match(&line) {
        let captures = date_re.captures(&line).unwrap();
        let year = captures.at(1).unwrap().parse::<i32>().unwrap();
        let month = captures.at(2).unwrap().parse::<u32>().unwrap();
        let day = captures.at(3).unwrap().parse::<u32>().unwrap();
        latest_date = Some(Local.ymd(year, month, day));
        println!("date: {}", latest_date.unwrap());
    }

    if time_activity_re.is_match(&line) && latest_date != None {
        let captures = time_activity_re.captures(&line).unwrap();
        let hour = captures.at(1).unwrap().parse::<u32>().unwrap();
        let minute = captures.at(2).unwrap().parse::<u32>().unwrap();
        let activity = captures.at(3).unwrap();

        latest_datetime = Some(latest_date.unwrap().and_hms(hour, minute, 0));

        latest_activity = if activity.len() > 0 {
            Some(activity)
        } else {
            None
        };

        println!("time activity: {} |{}|", latest_datetime.unwrap(), activity);
    }
}
...

My error is:

   Compiling tt v0.1.0 (file:///home/chris/cloud/tt)
src/main.rs:69:55: 69:59 error: `line` does not live long enough
src/main.rs:69             let captures = time_activity_re.captures(&line).unwrap();
                                                                     ^~~~
src/main.rs:55:5: 84:6 note: in this expansion of for loop expansion
src/main.rs:53:51: 86:2 note: reference must be valid for the block suffix following statement 7 at 53:50...
src/main.rs:53     let mut latest_activity : Option<&str> = None;
src/main.rs:54 
src/main.rs:55     for wrapped_line in reader.lines() {
src/main.rs:56         let line = wrapped_line.unwrap();
src/main.rs:57         println!("line: {}", line);
src/main.rs:58 
               ...
src/main.rs:56:42: 84:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 56:41
src/main.rs:56         let line = wrapped_line.unwrap();
src/main.rs:57         println!("line: {}", line);
src/main.rs:58 
src/main.rs:59         if date_re.is_match(&line) {
src/main.rs:60             let captures = date_re.captures(&line).unwrap();
src/main.rs:61             let year = captures.at(1).unwrap().parse::<i32>().unwrap();
               ...
error: aborting due to previous error
Could not compile `tt`.

I think the problem is that the latest_activity : Option<&str> lives longer than line inside the loop iteration where latest_activity is reassigned.

Is the correct?

If so, what's the best way of fixing it. The cost of allocating a new string does not bother me, though I would prefer not to do that for each iteration.

I feel I may need a reference-counted box to put the activity in - is this the right approach?

I could allocate a String outside of the loop - but how can I do so before I know how big it will need to be?


回答1:


The problem is that you are already allocating a new string for every iteration (there's nowhere for the Lines iterator to store a buffer, so it has to allocate a fresh String for each line), but you're trying to store a slice into it outside the loop.

You also can't really know how big an externally allocated String would need to be in this case... so typically you wouldn't worry about it and just resize as necessary.

The simplest way is probably to make latest_activity an Option<String>. When you want to change it, you can use .clear() followed by .push_str(s) (see the String documentation). This should re-use the existing allocation if it's large enough, resizing if it isn't. It might require some re-allocating, but nothing major (provided you don't, for example, try to store increasingly longer and longer strings).

Another possibility would be to just store wrapped_line itself, moving it out of the loop. You could store that alongside the slice indices, and then do the actual slicing outside the loop (no, you can't just store the String and the &str slice separately or together with just standard library types).



来源:https://stackoverflow.com/questions/33781625/how-to-allocate-a-string-before-you-know-how-big-it-needs-to-be

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!