В главе 13 книги Rust вы реализуете структуру Cacher
для отложенной инициализации, чтобы продемонстрировать использование замыканий и функционального программирования. В качестве упражнения они поощряют читателя попытаться создать шаблон c Cacher
, который может хранить более одного значения. Для этого они рекомендуют использовать Hashmap
.
Попробуйте изменить Cacher так, чтобы он содержал карту ha sh, а не одно значение. Ключи карты ha sh будут передаваемыми значениями arg, а значения карты ha sh будут результатом вызова замыкания для этого ключа. Вместо того, чтобы посмотреть, имеет ли self.value непосредственное значение Some или None, функция value ищет аргумент на карте ha sh и возвращает значение, если оно присутствует. Если он отсутствует, Cacher вызовет замыкание и сохранит полученное значение в карте ha sh, связанной с его значением arg.
Вторая проблема с текущей реализацией Cacher заключается в том, что он принимает только замыкания, которые взять один параметр типа u32 и вернуть u32. Например, мы можем захотеть кэшировать результаты замыканий, которые берут фрагмент строки и возвращают значения usize. Чтобы решить эту проблему, попробуйте ввести более общие параметры c, чтобы повысить гибкость функции Cacher.
Для решения этого упражнения я использовал следующий код:
struct Cacher<T, K, V>
where T: Fn(K) -> V
{
calculation: T,
values: HashMap<K, V>,
}
impl<T, K, V> Cacher<T, K, V>
where T: Fn(K) -> V,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
fn new(calculation: T) -> Cacher<T, K, V> {
Cacher {
calculation,
values: HashMap::new(),
}
}
fn value(&mut self, intensity: K) -> &V {
self.values.entry(intensity.clone()).or_insert((self.calculation)(intensity))
}
}
Этот код компилируется и выполняется, но не является правильным Cacher
из-за того, что (self.calculation)(intensity)
всегда выполняется. Даже когда запись существует. Из документации и примеров я понимаю, что функция Entry::or_insert
выполняется только в том случае, если Entry
не существует.
Мне известно о решении упражнения из вопроса Возможно ли это использовать один шаблон c для ключа и значения HashMap? , но я хотел бы знать, возможно ли решить проблему так, как я это делаю в настоящее время.
Редактировать : Как поясняется в комментарии: or_insert_with
не решает проблему. При попытке or_insert_with(|| (self.calculation)(intensity.clone()))
я получаю следующую ошибку error[E0502]: cannot borrow self as immutable because it is also borrowed as mutable
.