Reputation: 1926
The following Rust code doesn't compile.
extern create byteorder;
use byetorder::{LittleEndian, ReadBytesExt};
fn main() {
let buf: [u8; 12] = [
0x00, 0x42, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x30,
];
let id = &buf[0..1].read_u16::<LittleEndian>(); }
The message from the compiler:
error[E0599]: no method named `read_u16` found for type `[u8]` in the current scope
--> src/main.rs:18:25
|
18 | let id = &buf[0..1].read_u16::<LittleEndian>();
| ^^^^^^^^
|
= note: the method `read_u16` exists but the following trait bounds were not satisfied:
`[u8] : byteorder::ReadBytesExt`
There are very similar questions on Stack Overflow, which I have reviewed, but mine is subtly different from those because I'm trying to read a u16
from a slice. In practice, I'm not sure why my example is substantively different, I'm sure I'm missing something obvious.
Specifically, it's not clear to me how what I've got is meaningfully different from what's in the accepted answer here:
How can I convert a buffer of a slice of bytes (&[u8]) to an integer?
Don't I also have &[u8]
when I say &buf[0..1]
?
Upvotes: 4
Views: 5362
Reputation: 601421
Your code calls read_u16()
on an array rather than a slice. You probably intend to call the method on &buf[0..1]
, but due to operator precedence you actually call it on buf[0..1]
. This can be fixed by simply adding a pair of parentheses:
let id = (&buf[0..1]).read_u16::<LittleEndian>();
Your original code is interpreted as &(buf[0..1].read_u16::<LittleEndian>())
, which is why the compiler complains that the ReadBytesExt
trait is not implemented for [u8]
.
Upvotes: 7
Reputation: 430416
Because the trait bounds were not satisfied.
read_u16
needs the receiver to be a mutable reference:
pub trait ReadBytesExt: Read {
fn read_u16<T: ByteOrder>(&mut self) -> Result<u16> { ... }
}
This is because it will call Read
, which requires the same:
impl<'a> Read for &'a [u8] {
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
}
Note that Read
is implemented for &[u8]
, but takes &mut self
. That means that self
is a &mut &[u8]
, a mutable reference to a slice.
Introducing parenthesis, as suggested by Sven Marnach, creates a slice (&[u8]
) as a temporary value and temporary values can be treated as implicitly mutable.
In the linked question, the starting variable is a slice that is mutable. Calling read_u16
can take a mutable reference to buf
:
let mut buf: &[u8] = &[0x00, 0x42];
In your case, you have an array. While this dereferences to a slice, Rust's automatic (de)referencing rules will never add two levels of reference. Method lookup fails.
See also:
Upvotes: 0