Owned types as parameters
drdo opened this issue · comments
Maybe I misunderstood something, but it seems that markup.rs always adds a reference to whatever types you use.
Consider the following code:
markup::define! {
Foo<X: Render, I: Iterator<Item = X>>(items: I) {
@for i in items {
p { @i }
}
}
}
This does not compile, it complains that Iterator
is not implemented for &I
.
Why is this the case? Why can't I just pass the type I
itself?
What would be the correct way to implement something similar to the code above?
Hi,
This is because of how the Render
trait is implemented: a template can be rendered multiple times after it's created once. If the fields of the template were available directly inside the template, this would not be possible as all the fields would need to be moved out of the struct on the first render.
What kind of values will you be passing to this template? One solution could be to accept Clone
able iterators (many iterators in Rust are cheap to clone):
markup::define! {
Foo<X: markup::Render, I: Iterator<Item = X> + Clone>(items: I) {
@for i in items.clone() {
p { @i }
}
}
}
fn main() {
println!(
"{}",
Foo {
items: vec![1, 2, 3].iter()
}
);
}
Cloning an iterator in this case is extremely cheap (just a couple of pointers IIRC).
I'm wondering. Why would a template need to be rendered multiple times?
Can you not just create and consume a new instance each time?
I don't remember exactly, but I think the primary reason I went for this approach is because otherwise templates couldn't implement std::fmt::Display
because Display::fmt
takes &self
.
Alright, thanks.