Я сейчас нахожусь в процессе изучения Rust. В главе 13 из книги в этой части приведен пример Cacher
struct . Идея, лежащая в основе кэширования, заключается в том, что значение оценивается только после того, как оно запрошено, а затем сохранено. В этом примере ввод кэша равен i32
, а также вывод i32
. Поскольку я хотел сделать его немного более полезным, я хотел, чтобы кэшировщик не брал никаких входных данных и генерировал значение любого типа (в основном тип Lazy<T>
из .NET , если вы знакомы).
Моей первой идеей было просто изменить заданную Cacher
с помощью общих аннотаций, например, так:
struct Cacher<TCalc, TVal>
where TCalc: Fn() -> TVal
{
calculation: TCalc,
value: Option<TVal>,
}
impl<TCalc, TVal> Cacher<TCalc, TVal>
where TCalc: Fn() -> TVal
{
fn new(calculation: TCalc) -> Cacher<TCalc, TVal> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self) -> TVal {
match self.value { // cannot move out of `self.value.0` which is behind a mutable reference
Some(v) => v,
None => {
let v = (self.calculation)();
self.value = Some(v);
v // use of moved value: `v`
},
}
}
}
Как вы можете заметить, комментируя комментарии, это породило некоторые ошибки на моем пути в *Метод 1019 *.
Затем я попробовал много вещей и нашел рабочее решение для метода value
. Обратите внимание, что теперь он возвращает &TVal
вместо TVal
, но это меня совсем не беспокоит.
fn value(&mut self) -> &TVal {
if let None = self.value {
let v = (self.calculation)();
self.value = Some(v);
}
self.value.as_ref().unwrap()
}
Я могу создать и использовать этот кэшир так:
let mut expensive_val = Cacher::new(|| {
println!("Calculating value..");
"my result"
});
println!("Cacher was created.");
println!("The value is '{}'.", expensive_val.value());
println!("The value is still '{}'.", expensive_val.value());
// Cacher was created.
// Calculating value..
// The value is 'my result'.
// The value is still 'my result'.
Это прекрасно работает, но я чувствовал, что наличие двух аргументов типа для этого избыточно, поэтому я попытался удалить первый (TCalc
). После некоторого исследования я придумал следующее:
struct Cacher<'a, T>
{
calculation: &'a dyn Fn() -> T,
value: Option<T>,
}
impl<'a, T> Cacher<'a, T>
{
fn new(calculation: &'a dyn Fn() -> T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self) -> &T {
if let None = self.value {
let v = (self.calculation)();
self.value = Some(v);
}
self.value.as_ref().unwrap()
}
}
Этот кешер все еще работает, но теперь я должен передать ссылку на замыкание вместо самого замыкания.
let mut expensive_val = Cacher::new(&|| { // Note the &
println!("Calculating value..");
"my result"
});
Iне вижу в этом никакого недостатка, но есть ли способ сделать это без ссылки? Я имею в виду с одним параметром типа и все еще передавая закрытие вместо ссылки. Простая попытка сохранить Fn() -> T
напрямую приведет к the size for values of type `(dyn std::ops::Fn() -> T + 'static)` cannot be known at compilation time
.
Ps. Может быть, я сказал что-то неправильно, или не так, как вы делаете это в ржавчине , поэтому, если вы можете исправить меня, пожалуйста, сделайте:)