I need to distinguish how to print items of a vec based on a runtime parameter and some other runtime information. I am struggling a bit to make this work with boxed closures.
This seems to be the decorator pattern, but I can't seem to make it work. Please note that the function write_vec
needs to be re-used and can contain other runtime information, which is why I need it declared . The problem is how to move a boxed closure to inside a closure without making the function FnOnce. Alternatively, how to pass a reference to the closure without leaking f
use std::fmt::{Debug, Formatter, Result, Write};
enum Type {
Date,
Int,
}
struct TypedVec {
data: Vec<i32>,
type_: Type,
}
fn get_write_value<'a, F: Write>(
vec: &'a TypedVec,
) -> Box<dyn Fn(&mut F, usize) -> Result + 'a> {
match vec.type_ {
Type::Int => Box::new(|f, index| write!(f, "{}", vec.data[index])),
Type::Date => Box::new(|f, index| write!(f, "{}-{}-{}", vec.data[index] / 365, (vec.data[index] % 365) / 30, vec.data[index] % 30)), // this is wrong, it does not matter
}
}
fn write_vec<D, F>(
f: &mut F,
d: D,
index: usize,
len: usize,
) -> Result
where
D: Fn(&mut F, usize) -> Result,
F: Write,
{
if index == 0 {
f.write_char('[')?;
}
if index != 0 {
f.write_char(',')?;
f.write_char('\n')?;
}
d(f, index)?;
if index + 1 == len {
f.write_char(']')?;
}
Ok(())
}
impl Debug for TypedVec {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let writer = get_write_value(self);
let write = |f: &mut Formatter<'_>, index| write_vec(f, writer, index, self.data.len());
for i in 0..self.data.len() {
write(f, i)?;
}
Ok(())
}
}
fn main() {
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0521]: borrowed data escapes outside of closure
--> src/main.rs:50:52
|
48 | let writer = get_write_value(self);
| ------ `writer` declared here, outside of the closure body
49 |
50 | let write = |f: &mut Formatter<'_>, index| write_vec(f, writer, index, self.data.len());
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `f` escapes the closure body here
| |
| `f` is a reference that is only valid in the closure body
|
= note: requirement occurs because of a mutable reference to Formatter<'_>
= note: mutable references are invariant over their type parameter
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error[E0382]: use of moved value: `write`
--> src/main.rs:53:13
|
53 | write(f, i)?;
| ^^^^^------
| |
| `write` moved due to this call, in previous iteration of loop
|
note: closure cannot be invoked more than once because it moves the variable `writer` out of its environment
--> src/main.rs:50:65
|
50 | let write = |f: &mut Formatter<'_>, index| write_vec(f, writer, index, self.data.len());
| ^^^^^^
note: this value implements `FnOnce`, which causes it to be moved when called
--> src/main.rs:53:13
|
53 | write(f, i)?;
| ^^^^^
Some errors have detailed explanations: E0382, E0521.
For more information about an error, try `rustc --explain E0382`.
error: could not compile `playground` due to 2 previous errors