I'm trying to implement the following idea:
let command = ...;
let request = match subcommand {
Some(x) => [command, x as u8, (x >> 8) as u8],
None => [command],
};
request
should be either an array of 1 (in case there is no subcommand) or 3 (in case there is a 2-byte subcommand). Obviously this approach does not work because branches of match expressions "return" different types (either [u8;1] or [u8;3]);
My logical follow-up was to use slices:
let request: &[u8] = match subcommand {
Some(x) => &[...],
None => &[...],
};
That works great on constant values such as &[0, 0, 0]
, but when I'm trying to build arrays using my variables it fails with temporary value dropped while borrowed
.
I got that in that case my reference is escaping to the superior code block, but is there a way around it (i.e some lifetime annotation?)
Creating the buffer beforehand and using slices does work but does not feel optimal.
UPD: that's the function I'm trying to debug:
// Read the data from the device.
async fn read<R>(&mut self, command: u8, subcommand: Option<u16>) -> Result<R, ChipError<E>>
where
R: TryFrom<u16>,
{
// If the caller has provided a subcommand, build the request with command and subcommand.
// If there is no subcommand, use the plain command instead
let request: &[u8] = match subcommand {
Some(x) => &[command, x as u8, (x >> 8) as u8],
None => &[command],
};
// Send the bytes to the device
self.i2c.write(self.addr, &request).await?;
// And read the response...
let mut response = [0, 0];
self.i2c
.write_read(self.addr, &[commands::CONTROL], &mut response)
.await?;
match u16::from_le_bytes(response).try_into() {
Ok(value) => Ok(value),
Err(_) => Err(ChipError::Value),
}
}
And that's the compiler output:
error[E0716]: temporary value dropped while borrowed
--> xxxx/src/lib.rs:69:25
|
68 | let request: &[u8] = match subcommand {
| ______________________________-
69 | | Some(x) => &[command, x as u8, (x >> 8) as u8],
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| | | |
| | | temporary value is freed at the end of this statement
| | creates a temporary value which is freed while still in use
70 | | None => &[command],
71 | | };
| |_________- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
There are multiple ways you can do this. Here are some suggestions.
Vec
(orBox<[u8]>
). Yes, it is less efficient, but does it matter for you? it is likely to be the clearest solution.ArrayVec
.