Cannot infer an appropriate lifetime for autoref


#1

I have a struct and impl with the 'a lifetime set…

pub struct Profile<'a> {
	pub patterns: PatternMap,
	pub pattern_total: u32,
	pub pattern_ranks: Vec<(&'a str, f64)>,

and so on

impl<'a> Profile<'a> {
	//constructor
	pub fn new() -> Profile<'a> {

and so on

inside the impl I have the following function …

	pub fn cum_patternmap(&mut self) ->  Vec<(&'a str, f64)> {
		let mut patterns: Vec<(&'a str, f64)> = self.patterns.iter().map(|t| (&**t.0, (*t.1 as f64 / self.pattern_total as f64) * 100.0)).collect::<Vec<(_,_)>>();
		patterns.sort_by(|&(_, a), &(_, b)| b.partial_cmp(&a).unwrap());
		patterns.into_iter().scan(("", 0.00 as f64), |state, (ref k, v)| {
			*state = (&*k, state.1 + &v);
			Some(*state)
		}).collect::<Vec<(_,_)>>()
	}

I’m calling it from another function within impl

	pub fn pre_generate(&mut self){
		self.cum_sizemap();
		self.pattern_ranks = self.cum_patternmap();
	}

When I try to compile I get the following error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src\test_data_generator\profile\profile.rs:81:57
   |
81 |            let mut patterns: Vec<(&'a str, f64)> = self.patterns.iter().map
(|t| (&**t.0, (*t.1 as f64 / self.pattern_total as f64) * 100.0)).collect::<Vec<
(_,_)>>();
   |                                                                  ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th
e method body at 80:2...
  --> src\test_data_generator\profile\profile.rs:80:2
   |
80 | /  pub fn cum_patternmap(&mut self) ->  Vec<(&'a str, f64)> {
81 | |          let mut patterns: Vec<(&'a str, f64)> = self.patterns.iter().map(|t| (&**t.0, (*t.1 as f64 / self.pattern_total as f64) * 100.0)).collect::<Vec<(_,_)>>();
82 | |          patterns.sort_by(|&(_, a), &(_, b)| b.partial_cmp(&a).unwrap());

83 | |          patterns.into_iter().scan(("", 0.00 as f64), |state, (ref k, v)| {
...  |
86 | |          }).collect::<Vec<(_,_)>>()
87 | |  }
   | |__^
note: ...so that reference does not outlive borrowed content
  --> src\test_data_generator\profile\profile.rs:81:43
   |
81 |            let mut patterns: Vec<(&'a str, f64)> = self.patterns.iter().map(|t| (&**t.0, (*t.1 as f64 / self.pattern_total as f64) * 100.0)).collect::<Vec<(_,_)>>();
   |                                                    ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl
 at 22:1...
  --> src\test_data_generator\profile\profile.rs:22:1
   |
22 | / impl<'a> Profile<'a> {
23 | |  //constructor
24 | |  pub fn new() -> Profile<'a> {
25 | |          Profile {
...  |
146| |  }
147| | }
   | |_^
note: ...so that expression is assignable (expected std::vec::Vec<(&'a str, f64)
>, found std::vec::Vec<(&str, f64)>)
  --> src\test_data_generator\profile\profile.rs:81:43
   |
81 |            let mut patterns: Vec<(&'a str, f64)> = self.patterns.iter().map(|t| (&**t.0, (*t.1 as f64 / self.pattern_total as f64) * 100.0)).collect::<Vec<(_,_)>>();
   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

I understand what the error message means, but cannot think of a way to resolve it. Mind you, self.patterns is a BTreeMap<String, u32>, and I need to keep the String

Does anyone have any ideas?


#2

Self-referential structs are not possible in safe Rust, because Profile can be memcpy'd to any address at any time. As soon as it’s copied outside of new it may have a new location in memory, which would invalidate all pointers inside it.

You should use some other way to refer to the elements, like an index into a Vec.

If you’re brave, you can make a Box<Profile> first (giving it a permanent address on the heap) and use raw pointers instead of references.


#3

As @kornel mentioned, self-referential structs are disallowed. I can see 3 non-exotic options:

  1. Wrap the String in an Rc. Not sure if this violates your requirement to keep a String.
  2. Clone the String in cum_patternmap
  3. Have Profile receive a reference to a PatternMap that’s been populated externally.

#4

Thanks for the answers everyone. I thought I was going crazy and overlooking an obvious solution.

I’ll try your suggestions.