Variable does not live long enough

Using to_owned is the better way of converting &str to String.

1 Like

It's faster, but requires an explicit import of std::borrow::ToOwned. Using to_string() is therefore quite a bit more convenient.

Yeah, but going through the format machinery isn't what you usually want for simply converting a &str to String, best practice is to use to_owned anyway – it's one import for the whole file.

1 Like

One import is less convenient than zero imports. (I thought I saw something about ToOwned getting into the prelude, which would fix that.)

Thanks. since I am learning, it is good to know all the possibility.

yeah, I can image 'var not live long enough situation' is not rare. besides, ownership is unique feature in rust, it is reasonable to make it convenient to do so.

I have another problem to get var out. if I comment out the commented line, compiler tell me 'use of possibly uninitialized variable:'

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;
use std::borrow::ToOwned;

fn main () {

    let lines = BufReader::new(File::open("./data/hello.txt").unwrap()).lines();

    let mut sample_name;

    for line in lines {
            let line_content = line.unwrap();
            if line_content.contains("Sample Name") {
               sample_name = line_content.split("\t").nth(1).unwrap().to_owned();
            }
    }   
 //   println!("{}", sample_name);
}

I can get it work by mimic the case of hashmap.(create it first and then put value to it)

let mut sample_name = String::new();

and then inside the block, push_str to sample_name

  sample_name.push_str(line_content.split("\t").nth(1).unwrap());

but it feel not natural. is it a better way to do this? Thanks.

You can use Option:

fn main () {
    let lines = BufReader::new(File::open("./data/hello.txt").unwrap()).lines();

    let mut sample_name = None;

        for line in lines {
            let line_content = line.unwrap();
            if line_content.contains("Sample Name") {
                sample_name = Some(line_content.split("\t").nth(1).unwrap().to_owned());
            }
        }

        if let Some(name) = sample_name {
            println!("{}", name);
        }
        else {
            // panic?
        }

}
2 Likes

I unwarped after nth already, so no option

I think it can be better written as:

sample_name = line_content.split("\t").nth(1).map(|s| s.to_owned());

since .nth() returns option already.

Edit
Or even this way:

sample_name = line_content.split("\t").nth(1).map(ToOwned::to_owned);
3 Likes

sorry, I did not saw your change in those two lines. I tried this, and it works. but I do not understand it.

why change the type of sample_name to Option and it works. what is wrong with my previous code? Thanks.

You left your sample_name uninitialized in declaration, so rustc complained, as it could be still uninitialized when used in println!() (if there are no lines, or no lines matching if criterion, this variable would never get assigned).

In case of Option, sample_name is initialized from very beginning with None value, and when (or if) some new value is found for it, it becomes Some(value). You see, no more uninitialized variable.

Then before usage in println!() you unwrap it with if let ensuraring it's not None, and then use it safely.

You can think of None as C's NULL, but typesafe and working for all types, not just for pointers.

1 Like

I notice the ToOwned is in the prelude, so I tried it.

https://github.com/rust-lang/rust/blob/master/src/libstd/prelude/v1.rs#L29

but I still can not use it without import. any idea?

Is your Rust up to date?

I update my rust in the morning, does not work. I update just now. still the same.

rustc 1.0.0-nightly (2baf34825 2015-04-21) (built 2015-04-22)

If I uncomment the use, it work.

//use std::borrow::ToOwned;

Very odd. It landed five days ago: std: Add Default/IntoIterator/ToOwned to the prelude · rust-lang/rust@8f5b5f9 · GitHub

not in the nightly doc either

update: now it is in 1.1 nightly and the api doc.

with use std::borrow::ToOwned;

without

my example code right?

to_string is the way to go, based on the discussion here.