The following code snippet does the same things in 3 ways.
use std::collections::HashMap;
struct Foo {
cache: HashMap,
}
impl Foo
Rust doesn't handle this sort of caching well at the moment.
The best solution is to avoid the problem altogether. Does show_impl
really need to be a method of Foo
? If not, you can define a new trait and implement it for String
. For example:
trait ShowImpl: std::fmt::Display {
fn show_impl(&self) {
println!("{}", self);
}
}
impl ShowImpl for String {}
Then just call show_impl
on the string: self.get_cached(key).show_impl();
Here is a solution that uses UnsafeCell
. I'm not sure if it works correctly. While it does compile, the use of unsafe code means the compiler can no longer guarantee safety.
use std::collections::HashMap;
use std::cell::UnsafeCell;
struct Foo {
cache: UnsafeCell<HashMap<String, String>>,
}
impl Foo {
fn get_cached(&self, key: &String) -> &String {
unsafe {
if !(*self.cache.get()).contains_key(key) {
(*self.cache.get()).insert(key.clone(), String::from("default"));
}
(*self.cache.get()).get(key).unwrap()
}
}
fn show_impl(&self, what: &String) {
println!("{}", what);
}
pub fn show1(&mut self, key: &String) {
println!("{}", self.get_cached(key));
}
pub fn show2(&mut self, key: &String) {
unsafe {
if !(*self.cache.get()).contains_key(key) {
(*self.cache.get()).insert(key.clone(), String::from("default"));
}
self.show_impl((*self.cache.get()).get(key).unwrap());
}
}
pub fn show3(&self, key: &String) {
self.show_impl(self.get_cached(key));
}
}
fn main() {}
You could try to add &mut
on self
on show_impl
as in
...
fn show_impl(&self, what: &String)
...
So it won't get mixed.