1

I am trying to set the lifetime on a new vector of a particular type. I understand about lifetimes and borrowing. That is not the problem. The problem is the actual syntax to set the lifetime to <'a>.

I keep getting an error about the vector not living long enough, but when I try and set the lifetime I get a different error. Here is what my code looks like.

#[derive(Clone, Copy, Debug)]
pub struct ProfessorGroup<'a> {
    name: &'a str,
    gender: Gender,
    professors: &'a Vec<Professor<'a>>,
    rank: ProfessorRank,
    attrition_rate:f64,
    promotion_rate:f64,
    hiring_rate:f64,
    current_number:i32,
}
impl<'a> Default for ProfessorGroup<'a>{
    fn default() -> ProfessorGroup<'a>{
        ProfessorGroup {
            name: "uninitialized group",
            gender: Gender::Female,
            professors:&mut Vec<'a>::<Professor<'a>>::new(),//PROBLEM CODE
            rank: ProfessorRank::Assistant,
            attrition_rate: 0.0,
            promotion_rate: 0.0,
            hiring_rate: 0.0,
            current_number: 0,
        }
        }
}

The error I am getting is:

error: expected `:`, found `>`
  --> src/Actors/ProfessorGroups.rs:21:35
   |
21 |             professors:&mut Vec<'a>::<Professor<'a>>::new(),
   |                                   ^

error[E0063]: missing fields `attrition_rate`, `current_number`, `hiring_rate` and 3 other fields in initializer of `Actors::ProfessorGroups::ProfessorGroup<'_>`

The error seems to kill access to the fields below--hence the missing fields comment.

I tried professors:&mut <'a>Vec::<Professor<'a>>::new(), but that gave the same error.

I took out the lifetime altogether professors:&mut Vec::<Professor<'a>>::new(), but that just gave me an error that the vector was not living long enough.

I looked through the documentation but the closest I found was something like this, which did not work either: https://users.rust-lang.org/t/why-cant-i-specify-type-parameters-directly-after-the-type/2365

Can anyone see where I am making an error in the syntax?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
krishnab
  • 9,270
  • 12
  • 66
  • 123
  • 1
    Why is `professors` a reference to `Vec` rather than just a normal (owning) `Vec`? Do you actually want the ownership to be external? – ildjarn May 09 '17 at 16:27
  • Ah good point. I think I just got confused between the &self and the inclusion of the vector. Yeah, that makes sense. – krishnab May 09 '17 at 16:30
  • I will try that. But do you know how to add a lifetime to a vector? I looked around in the documentation but could not find it. – krishnab May 09 '17 at 16:30
  • 1
    you can't do it. A lifetime describes a constraint for your code that you are asking the compiler to verify, you can't force a lifetime. [As the book puts it "lifetimes are descriptive, not prescriptive"](https://doc.rust-lang.org/book/lifetimes.html); you can't create a `Vec` inside `default` and have a reference to it escape the method – Paolo Falabella May 09 '17 at 16:35
  • Okay I see. I did not see that in the book. Thanks for the suggestions @PaoloFalabella – krishnab May 09 '17 at 16:37
  • @ildjarn Okay, I think I am getting a better picture of the how this works in Rust. Thanks for the kind feedback. – krishnab May 09 '17 at 16:39
  • I do not know very well what you want to achieve in the end, but maybe I can use `use std::cell::RefCell;` In this question there are some links and an answer that maybe is what you are looking for http://stackoverflow.com/questions/36413364/as-i-can-make-the-vector-is-mutable-inside-struct – Angel Angel May 09 '17 at 17:23

1 Answers1

3

Reduced, you end up with something like

struct Professor<'a>(&'a u8);

pub struct ProfessorGroup<'a> {
    professors: &'a Vec<Professor<'a>>,
}

impl<'a> Default for ProfessorGroup<'a> {
    fn default() -> ProfessorGroup<'a> {
        ProfessorGroup {
            professors: &mut Vec<'a>::<Professor<'a>>::new(), 
        }
    }
}

In order:

  1. As mentioned, you can't return a reference. Convert the member to a Vec, not a &Vec. Additionally, you want to match &mut value to &mut Type and &value to &Type, don't cross them.
  2. Remove the first <'a> to get: Vec::<Professor<'a>>::new(). This compiles.
  3. Realize you don't have to do that because the entire point of type inference is to reduce the amount of stuff you tell the compiler. You can just type Vec::new().

Vec also implements Default itself, so for this small example, you can just #[derive(Default)]. If it makes sense, you could just implement (or derive) Default for all the component types.


I understand about lifetimes and borrowing. That is not the problem.

You may wish to re-evaluate your confidence in this statement, due to this part of the line:

professors: &mut Vec<'a>::<Professor<'a>>::new()
//          ^^^^

You cannot return a reference to a value created in a function, no exceptions. Lifetimes prevent this.

You should also review how to create a Minimal, Complete, Verifiable Example. In this case, why do you have 8 fields that have nothing to do with your problem? Why did you not share the definition of all the types you included anyway? When trying to understand any programming problem, reduce it until only the problem remains.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    Ahh, thanks for the guidance here. Yes, I will make sure to shorten my code samples in the future. I really appreciate your thorough answers. They really help a lot. The biggest issue for newbies, like me, to a language are good examples of well written code. So I think I will go through some more of the past answers on Rust questions to find good examples. Hopefully that will improve my understanding of the lifetimes and borrowing, etc. :). – krishnab May 09 '17 at 17:58