askama
askama copied to clipboard
problem accessing self.vec in for loop because "cannot move out of dereference"
Same problem as #107, but I can't see the issue with my code.
The error:
cannot move out of dereference of `std::sync::RwLockReadGuard<'_, Vec<std::string::String>>`
move occurs because value has type `Vec<std::string::String>`, which does not implement the `Copy` trait
The code:
#[derive(Template, Debug)]
#[template(
source = "
Time is now {{ now }}<ul>{% for i in patients.read().unwrap() %}<li>{{i}}</li>{% endfor %}</ul>
",
ext = "txt",
print = "code"
)]
pub(crate) struct PatientListView {
patients: Arc<RwLock<Vec<String>>>,
}
impl PatientListView {
fn debug(&self) {
for i in self.patients.read().unwrap().iter() {
println!("i: {}", i);
}
}
}
Help :-)
In the generated code askama invokes Vec::into_iter(), which tries to consume the vector, which gives to the error you posted. You need to "convince" askama to use an Iterator instead of an IntoIterator by calling .iter() explicitly. This means that you have to store the read guard in a variable first, though:
#[template(
source = "
{%- let guard = patients.read().unwrap() -%}
<ul>{% for i in guard.iter() %}<li>{{i}}</li>{% endfor %}</ul>
{%- let _ = guard -%}
",
ext = "txt",
print = "code"
)]
Hmm, maybe we should have the generator produce a variable for the for-loop expression instead. Then we avoid situations where that is needed to be done manually.
Additionally, the for-loop might be needed to be wrapped in an addiction block. To avoid locks not being released after the for-loop.
Thoughts @Kijewski @djc?
@vallentin, the iterator is stored in _iter
.
The problem is that calling iter() in line 644 fails some test with "type annotations needed", so I guess we are stuck with the into_iter() call.
Additionally, the for-loop might be needed to be wrapped in an addiction block.
You are right! I added {%- let _ = guard -%}
to my previous comment.
In the generated code askama invokes Vec::into_iter(), which tries to consume the vector, which gives to the error you posted. You need to "convince" askama to use an Iterator instead of an IntoIterator by calling .iter() explicitly. This means that you have to store the read guard in a variable first, though:
#[template( source = " {%- let guard = patients.read().unwrap() -%} <ul>{% for i in guard.iter() %}<li>{{i}}</li>{% endfor %}</ul> {%- let _ = guard -%} ", ext = "txt", print = "code" )]
This works perfectly. thank you
the iterator is stored in _iter.
Ahh, right
The problem is that calling iter() in line 644 fails some test with "type annotations needed", so I guess we are stuck with the into_iter() call.
Back to the drawing board then :)
I don't know if it would be possible to automatically divine when it's possible to call .iter(). I guess if it's possible to use .iter(), then you also want to use .iter() instead of .into_iter() in 99% of the use cases. But actually I did not pay enough attention why a type annotation is needed in here, though. :-/
A for
loop always calls into_iter()
on its Expression
. If the template calls iter()
on it, the resulting type should already be an Iterator
and so calling into_iter()
on that should have no effect.