Hello!
Rust beginner here! I'm learning Rust, and in part of my pet project, I have created a caching object, and I'm trying to understand the error messages the compiler is giving me. I tried trimming it down to a minimal example that still gives the error:
use std::collections::HashMap;
struct UT<'a> {
x: &'a str,
}
struct Factory {
a: String
}
impl Factory {
fn new() -> Self {
Self {
a: "ABC".to_string()
}
}
fn get_ut(&self) -> UT {
// Some expensive operations here
UT {
x: &self.a
}
}
}
struct Test<'a> {
f: Factory,
cache: HashMap<String, UT<'a>>
}
impl<'a> Test<'a> {
fn get_entry(&mut self, key: String) -> &'a str {
if !self.cache.contains_key(&key) {
let u = self.f.get_ut();
self.cache.insert(key.clone(), u);
}
self.cache.get(&key).unwrap().x
}
}
fn main() {
let mut t = Test {
f: Factory::new(),
cache: HashMap::new()
};
t.get_entry("A".to_string());
}
The error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:34:28
|
34 | let u = self.f.get_ut();
| ^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 32:5...
--> src/main.rs:32:5
|
32 | / fn get_entry(&mut self, key: String) -> &'a str {
33 | | if !self.cache.contains_key(&key) {
34 | | let u = self.f.get_ut();
35 | | self.cache.insert(key.clone(), u);
... |
38 | | self.cache.get(&key).unwrap().x
39 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:34:21
|
34 | let u = self.f.get_ut();
| ^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 31:6...
--> src/main.rs:31:6
|
31 | impl<'a> Test<'a> {
| ^^
note: ...so that the expression is assignable
--> src/main.rs:35:44
|
35 | self.cache.insert(key.clone(), u);
| ^
= note: expected `UT<'a>`
found `UT<'_>`
I've spent a few hours trying to think of why the error occurs, and I think it is because f
can be moved out at any time and dropped and the UT
s will no longer be valid?
Some other questions:
-
I'm still confused why
let u = self.f.get_ut();
can not live past the end of the method in the first conflict?self
is borrowed, so I thoughtu
would be valid untilself
is dropped? -
I think what I want is to tie the lifetime of the cache
UT
s to the factoryf
but I don't think I can do it without makingf
a&'a Factory
? -
And at the end, it says it wants a
UT<'a>
. Isn't that what it gets? Since the lifetime is tied to the HashMap which is part ofTest
so the lifetimes should be related?
I tried making f
a reference and it works: Playground link but I have no idea why.
My goal is more to understand why this is the wrong way to do it, rather than just getting it working
Please forgive me if these are silly questions.