Hi everybody,
I came from Java world and exploring Rust by trying to implement similar approaches. I understand that something might not work as I expected and my code doesn't make sense, but my aim is to intentionally face such issues. I would greatly appreciate if you point me to the right direction.
So I've started with creating custom file format which stores values as bytes. I have RawFormatBytes
struct to hold Vec
of tuples
(bytes_length, bytes) and business object Rate
which holds strings
and float
prices.
struct Rate<'a> {
arrival: &'a str,
price: f32,
reason: &'a str,
}
struct RawFormatBytes<'a> {
arrival_dates: Vec<(u8, &'a [u8])>,
prices: Vec<(u8, &'a [u8])>,
reasons: Vec<(u8, &'a [u8])>,
}
impl<'a> RawFormatBytes<'a> {
pub fn new() -> RawFormatBytes<'a> {
RawFormatBytes {
arrival_dates: Vec::new(),
prices: Vec::new(),
reasons: Vec::new(),
}
}
}
What I'm trying to do is to pass RawFormatBytes
holder to a Rate
's to_byte_format
method which fills in RawFormatBytes
's byte tuples from self fields.
impl<'a> Rate<'a> {
fn to_byte_format(&'a self, raw_bytes: &'a mut RawFormatBytes<'a>) {
raw_bytes.arrival_dates.push((self.arrival.as_bytes().len() as u8, self.arrival.as_bytes()));
raw_bytes.reasons.push((self.reason.as_bytes().len() as u8, self.reason.as_bytes()));
raw_bytes.prices.push((self.price.to_ne_bytes().len() as u8, self.price.to_ne_bytes().as_ref()));
}
}
It works fine until I want to store price bytes.
When I push self.price.to_ne_bytes()
to my holder,I got creates a temporary which is freed while still in use
and I'm fine with this. So I tried to .copy()
my price, but again it doesn't make sense, as the copied value is freed when the method ends. Unfortunately, to_ne_bytes()
consumes the value and I can do nothing with it.
error[E0716]: temporary value dropped while borrowed
--> src\main.rs:46:70
|
43 | impl<'a> Rate<'a> {
| -- lifetime `'a` defined here
...
46 | raw_bytes.prices.push((self.price.to_ne_bytes().len() as u8, self.price.to_ne_bytes().clone().as_ref()));
| -------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------ temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| argument requires that borrow lasts for `'a`
So my question is, what is the right approach to emerge a variable from a method which will be bound to caller's method argument RawFormatBytes
lifetime? I.e. I want my Rate
's method to create a var which will be stored in RawFormatBytes
struct, thus assuming the struct's lifetime. Is it even possible?
Another question is, I simply don't understand why iter() borrows mutable ref more than one time? I expect that each iteration step borrows it and free after, so it's literately borrowed once-per-iteration, but it's not the case?
let mut bytes = RawFormatBytes::new();
let x = &mut bytes;
for rate in rate_array.iter() {
rate.to_byte_format(x);
}
error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> src\main.rs:86:29
|
86 | rate.to_byte_format(x);
| ^ mutable borrow starts here in previous iteration of loop
The main method is
fn main() {
let s1 = String::from("2020-01-01");
let s2 = String::from("reason1");
let r1 = Rate {
arrival: s1.as_str(),
reason: s2.as_str(),
price: 25.03,
};
let s3 = String::from("2022-02-02");
let s4 = String::from("reason2");
let r2 = Rate {
arrival: s3.as_str(),
reason: s4.as_str(),
price: 356.03,
};
let rate_array = [r1, r2];
let mut bytes = RawFormatBytes::new();
let x = &mut bytes;
for rate in rate_array.iter() {
rate.to_byte_format(x);
}
}
Again, my examples might not make sense in real world, but I would greatly appreciate what is the right way of thinking.
Thanks!