Return type when getting an object from a Vec

I want to retrieve the largest town, but i can't figure out what the return type should be.
When the code is like this,
the code completion tells me to 'try consider using the 'static lifetime: &'static '.
Is this the right way to do this?

fn get_largest_town(town_list:Vec<Town>)->&Town{
    let index = town_list.iter().enumerate()
    .min_by_key(|(_, s)| s.population)
    .map(|(i, _)| i).unwrap();
    
    return town_list.get(index).unwrap();
}

When you take an argument of type Vec<Town>, your function “takes ownership” of the Vec, meaning that it is destroyed when the function exits. You can't return a reference to an item in the Vec, because that item has also been destroyed.

Instead, you can change the argument type to &Vec<Town> to make your function “borrow” the Vec, meaning that it will still be around after the function returns. Rust will also ensure that the Vec is not mutated or destroyed while the borrowed &Town reference is still alive:

fn get_largest_town(town_list: &Vec<Town>) -> &Town {

You'll learn more about ownership and borrowing in Chapter 4 of The Rust Programming Language.

By the way, you can simplify this function to:

fn get_largest_town(town_list: &Vec<Town>) -> &Town {
    town_list.iter().max_by_key(|town| town.population).unwrap()
}

(I changed min_by_key to max_by_key, since it looks like you want the highest population rather than the lowest.)

Note: As you learn more about Rust, you'll also learn that you can use a slice reference &[Town] instead of &Vec<Town> in this function, but that's not important yet.

5 Likes

I want to pass a Vec (town_list) from the main into sub methods to manipulate the values in the objects it hold and maybe add/delete some objects as well.
Is something like this possible?
Would this be the right way to borrow the Vec to manipulate it?

fn main() {
let mut town_list:Vec<Town>  = Vec::new();
doSomething();
}

fn get_largest_town(town_list: &Vec<Town>) -> &Town {
    town_list.iter().max_by_key(|town| town.population).unwrap()
}

fn remove_town_largest_population(mut town_list:Vec<Town>) {
    let index = town_list.iter().enumerate()
    .min_by_key(|(_, s)| s.population)
    .map(|(i, _)| i).unwrap();
    
    town_list.remove(index);
}
fn doSomething(town_list:&Vec<Town>) {
   while !town_list.is_empty() {
      doSomething2();
   }
}
fn doSomething2(town_list:&Vec<Town>) {
let mut current_town= town_list.first().unwrap();
let mut highest_pop_town = get_smallest_sell_order;
if (current_town.elavation <= highest_pop_town  ) {
   doSomething;
   }
remove_town_largest_population(town_list);
}

Functions that can modify the vector must take an exclusive reference, &mut Vec<TownList>. The code should look something like this:

fn main() {
    let mut town_list: Vec<Town> = Vec::new();
    doSomething(&mut town_list);
}

fn get_largest_town(town_list: &Vec<Town>) -> &Town {
    town_list.iter().max_by_key(|town| town.population).unwrap()
}

fn remove_town_largest_population(town_list: &mut Vec<Town>) {
    let index = town_list.iter().enumerate()
    .min_by_key(|(_, s)| s.population)
    .map(|(i, _)| i).unwrap();
    
    town_list.remove(index);
}

fn doSomething(town_list: &mut Vec<Town>) {
    while !town_list.is_empty() {
        doSomething2(town_list);
    }
}

fn doSomething2(town_list: &mut Vec<Town>) {
    let current_town = town_list.first().unwrap();
    let highest_pop_town = get_largest_town(&town_list);
    if current_town.elavation <= highest_pop_town.elavation {
        doSomething(town_list);
    }
    remove_town_largest_population(town_list);
}

(Playground)

I currently get this error. cannot assign to `current_town.population` which is behind a `&` reference `current_town` is a `&` reference, so the data it refers to cannot be written with this line current_town.population = current_town.population - 20;
The following method should allow me to edit the objects right?
Is this the rust standard way to do something like this?

fn get_largest_town(town_list:&mut Vec<Town>)->&mut Town{
    let index = town_list.iter().enumerate()
    .min_by_key(|(_, s)| s.population)
    .map(|(i, _)| i).unwrap();
    return town_list.get_mut(index).unwrap();
}
doSomething2() {

 let current_town = town_list.first().unwrap();
    let highest_pop_town = get_largest_town(&town_list);
    if current_town.elavation <= highest_pop_town.elavation {
        current_town.population = current_town.population - 20;// An example of a calculation I could do
    }

Please do read the documentation. first() returns an (optional) &T, i.e. an immutable reference. If you want to mutate through a reference to the first element, use first_mut().

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.