I'm struggling with the borrow checker and hope anyone can give me a clue.
The relevant code is below:
// Doc: https://docs.rs/strum/latest/strum/trait.IntoEnumIterator.html
use strum::IntoEnumIterator;
// Doc: https://docs.rs/strum/latest/strum/derive.EnumIter.html
use strum_macros::EnumIter;
#[derive(EnumIter, Debug)]
pub enum Frequency {
Freq1m,
Freq1h,
Freq1d,
}
impl Frequency {
pub fn value(&self) -> i32 {
match self {
Frequency::Freq1m => 60,
Frequency::Freq1h => 3600,
Frequency::Freq1d => 86400,
}
}
pub fn display_name(&self) -> &'static str {
match self {
Frequency::Freq1m => "1m",
Frequency::Freq1h => "1h",
Frequency::Freq1d => "1d",
}
}
}
impl PartialEq for Frequency {
fn eq(&self, other: &Self) -> bool {
self.value() == other.value()
}
}
pub struct CodeExample {
frequency: Frequency,
}
impl CodeExample {
fn ui(&mut self, ui: &mut egui::Ui) {
for freq in Frequency::iter() { // move occurs
ui.selectable_value(&mut self.frequency, freq, freq.display_name()); // borrow of moved value
}
}
}
After trial and error, I know that if I add the Clone
and Copy
trait to my Frequency
, it will work. But why? My understanding is that the move in for freq in Frenquency::iter()
should be fine, right? The later borrow seems valid to me. What am I missing?
My understanding is that the move in for freq in Frenquency::iter() should be fine, right? The later borrow seems valid to me. What am I missing?
Arguments to functions in rust are evaluated strictly from left to right. So in
ui.selectable_value(&mut self.frequency, freq, freq.display_name());
because freq
is not Copy
, it is moved into the function parameters which renders it invalid, then you try to borrow the now invalid freq
in order to compute its display_name
. Hence use of a moved value.
Either make Frequency
Copy
(it's a trivial enum) or store freq.display_name()
in a local before calling the method. Copy
works because a value which is Copy
is... copied, rather than moved. So freq
remains valid after it is "moved" as a parameter, rather than become invalid.