I'm having trouble trying to get or insert a value in a HashMap:
pub struct Renderer {
shaders: HashMap<String, Box<Shader>>, // Shader being a trait
}
impl Renderer {
pub fn render() -> Result<(), Box<Error>> {
let shader = match self.shaders.entry(material.name.clone()) {
Entry::Occupied(entry) => entry.get(),
Entry::Vacant(entry) => {
let shader = Shader::try_from_material(context, material)?;
entry.insert(shader)
}
};
}
}
Note the ? inside the match, so I can't use the .or_insert entry method.
I'm getting the following error:
error[E0597]: `entry` does not live long enough
--> game/src/webgl_gltf/mod.rs:39:39
|
38 | let shader = match self.shaders.entry(material.name.clone()) {
| ------ borrow later stored here
39 | Entry::Occupied(entry) => entry.get(),
| ^^^^^ borrowed value does not live long enough
...
44 | };
| - `entry` dropped here while still borrowed
The error is kinda explicit, but I can't manage to get my head around the problem.
How would you get or insert a value in a HashMap, considering the insert may fail ?
Thanks!
Edit: I got one previous version working by using RC instead of Box, but Rc feel kind of unnecessary here
One thing to note before the answer, please use the syntax dyn Trait for dynamically dispatched traits. For example Box<dyn Shader> and Box<dyn Error>. This makes it clear that Shader is a trait that is being dynamically dispatched.
Also I think you didn't put the full signature of Renderer::render
If you want shader to live only for the duration of the render() function, you should be able to fix the error in the most straight-forward way – by making entry live long enough:
pub fn render() -> Result<(), Box<dyn Error>> {
let entry = self.shaders.entry(&material.name)
let shader = match entry { … };
}
This ensures that entry outlives shader, so it should fix the error.
Thanks for your answer, but this doesn't works either:
let entry = self.shaders.entry(material.name.clone());
let shader = match entry {
Entry::Occupied(occupied_entry) => occupied_entry.get(),
Entry::Vacant(vacant_entry) => {
let shader = Shader::try_from_material(context, material)?;
vacant_entry.insert(shader)
}
};
error[E0597]: `occupied_entry` does not live long enough
--> game/src/webgl_gltf/mod.rs:40:52
|
39 | let shader = match entry {
| ------ borrow later stored here
40 | Entry::Occupied(occupied_entry) => occupied_entry.get(),
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
45 | };
| - `occupied_entry` dropped here while still borrowed
It's the matched OccupiedEntry that does not live long enouth...
Instead of using occupied_entry.get() use occupied_entry.into_mut().
The difference is that get borrows the entry, so it must be outlived by the entry, but into_mut consumes the entry and gives you something you can use later.
Thanks, it looks like the way to go, now i'm getting another error
let shader = match self.shaders.entry(material.name.clone()) {
Entry::Occupied(entry) => Ok(&**entry.into_mut()),
Entry::Vacant(entry) => {
let shader = Shader::try_from_material(context, material)?;
Ok(&**entry.insert(shader))
}
};
--> game/src/webgl_gltf/mod.rs:39:43
|
38 | let shader = match self.shaders.entry(material.name.clone()) {
| ------ consider giving `shader` a type
39 | Entry::Occupied(entry) => Ok(&**entry.into_mut()),
| ^^ cannot infer type for `E`
And I have no idea where this E comes from (not from my code for sure...)