Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I return a Vec<&str> from a function?

Tags:

rust

I am trying to return a Vec<&str> but have been having issues converting u64 to &str inside the while loop:

fn latest_ids<'a>(current_id: u64, latest_id: u64) -> Vec<&'a str> {
    let mut ids: Vec<&str> = vec![];
    let mut start = current_id;
    while !(start >= latest_id) {
        start += 1;
        ids.push(start.to_string().as_str());
    }
    ids
}

cannot return value referencing temporary value

If I return just a Vec<String> then it works fine.

fn latest_ids<'a>(current_id: u64, latest_id: u64) -> Vec<String> {
    let mut ids: Vec<String> = vec![];
    let mut start = current_id;
    while !(start >= latest_id) {
        start += 1;
        ids.push(start.to_string());
    }
    ids
}

The next function that is called after this requires a &str type parameter so should I be returning a Vec<&str> or just return a Vec<String> and let the caller handle the conversion?

Next function to be called after getting the result of latest_ids():

pub fn add_queue(job: &Job, ids: Vec<&str>) -> Result<(), QueueError> {
    let meta_handler = MetaService {};

    match job.meta_type {
        MetaType::One => meta_handler.one().add_fetch_queue(ids).execute(),
        MetaType::Two => meta_handler.two().add_fetch_queue(ids).execute(),
        MetaType::Three => meta_handler.three().add_fetch_queue(ids).execute(),
    }
}
like image 452
James Avatar asked Oct 28 '22 15:10

James


1 Answers

The lifetime you've introduced is saying "I am returning a vector of string references whose lifetime outlives this function". That isn't true, because you're creating a String then storing a reference to it. That reference will die at the end of the scope the String is created in.

To answer your question purely from a "design" POV:

should I be returning a Vec<&str> or just return a Vec of String type and let the caller handle the conversion?

The method is called latest_ids .. and the ID's you're passing in are 64-bit integers. I think its acceptable given the name of the method that you should return 64-bit integers and the caller should do the conversion.

fn main() -> std::io::Result<()> {

    let ids: Vec<String> = latest_ids(5, 10).iter().map(|n| n.to_string()).collect();
    let ids_as_string_references: Vec<&str> = ids.iter().map(|n| &**n).collect();

    println!("{:?}", ids_as_string_references);

    Ok(())
}

fn latest_ids(current_id: u64, latest_id: u64) -> Vec<u64> {
    let mut ids = vec![];
    let mut start = current_id;
    while !(start >= latest_id) {
        start += 1;
        ids.push(start);
    }
    ids
}

Prints: ["6", "7", "8", "9", "10"]

The double handling here is because you asked for references. Depending on further context around the code, the double handling might not be required. If you update your question with more information about the next function that requires a vector of &str references I can update my answer to help redesign it.

like image 115
Simon Whitehead Avatar answered Nov 01 '22 19:11

Simon Whitehead