Я думаю, что здесь есть несколько вопросов, которые нужно рассмотреть:
Во-первых, для определения функции value(&mut self, k: K) -> &V
;компилятор вставит вам время жизни, чтобы оно стало value(&'a mut self, k: K) -> &'a V
.Это означает, что время жизни self
не может уменьшиться ради функции, потому что есть ссылка, выходящая из функции с тем же временем жизни, и будет жить столько же, сколько и область действия.Поскольку это изменчивая ссылка, вы не можете заимствовать ее снова.Следовательно, ошибка error[E0499]: cannot borrow cacher as mutable more than once at a time
.
Во-вторых, вы вызываете функцию calculation
, которая возвращает значение в некоторой внутренней области действия функции value()
, а затем вы возвращаете ссылку на нее, что невозможно.Вы ожидаете, что ссылка будет жить дольше, чем референт.Отсюда ошибка error[E0597]: v does not live long enough
Третья ошибка немного связана.Как видите, let result = self.values.get(&k);
, как упоминалось в первом утверждении, заставляет k
оставаться неизменным до конца функции.Возвращаемое значение result
будет действовать до тех пор, пока ваша функция value()
означает, что вы не можете взять заем (изменяемый) в той же области действия, что приводит к ошибке error[E0502]: cannot borrow self.values as mutable because it is also borrowed as immutable in value() self.values.get(&k)
Ваш K
должен бытьClone
, причина k
будет перемещена в функцию calculation
, что сделает ее непригодной для использования во время insert
.
Так что с K
в качестве Clone
реализация Cacher
будетbe:
impl<T, K: Eq + Hash + Clone, V> Cacher<T, K, V>
where
T: Fn(K) -> V,
{
pub fn new(calculation: T) -> Cacher<T, K, V> {
Cacher {
calculation,
values: hash_map::HashMap::new(),
}
}
pub fn value(&mut self, k: K) -> &V {
if self.values.contains_key(&k) {
return &self.values[&k];
}
self.values.insert(k.clone(), (self.calculation)(k.clone()));
self.values.get(&k).unwrap()
}
}
Это время жизни здесь основано на потоке управления ветвлением.Блок if self.values.contains_key ...
всегда возвращается, поэтому код после блока if
может быть выполнен только тогда, когда if self.values.contains_key ...
равен false
.Крошечная область, созданная для условия if
, будет жить только в рамках проверки условия, т.е. ссылка, полученная (и возвращенная) для if self.values.contains_key(...
, исчезнет с этой крошечной областью.
Для получения дополнительной информации см. NLL RFC
Как отметил @jmb в своем ответе, чтобы ваш тест работал, V
должен быть Clone
(impl <... V:Clone> Cacher<T, K, V>
) для возврата по значению или использования долевого владениянапример Rc
, чтобы избежать затрат на клонирование.
например.
fn value(&mut self, k: K) -> V { ..
fn value(&mut self, k: K) -> Rc<V> { ..