I am reading raw data from a file and I want to convert it to an integer:
fn main() { let buf: &[u8] = &[0, 0, 0, 1]; let num = slice_to_i8(buf); println!("1 == {}", num); } pub fn slice_to_i8(buf: &[u8]) -> i32 { unimplemented!("what should I do here?") }
I would do a cast in C, but what do I do in Rust?
Like a byte is a group of 8 bits, a buffer is a group of a pre-defined number of bytes. If we have a group of 3 bytes, this could either represent 3 values between 0 and 255, but also one single value between 0 and 16777216 (2563).
Byte slices are a list of bytes that represent UTF-8 encodings of Unicode code points. Taking the information from above, we could create a byte slice that represents the word “Go”: bs := []byte{71, 111}
A byte in Go is an unsigned 8-bit integer. It has type uint8 . A byte has a limit of 0 – 255 in numerical range. It can represent an ASCII character.
In go language, the buffer belongs to the byte package of the Go language, and we can use these package to manipulate the byte of the string. For example, suppose we have a string. We can read the length of the string with the len function, which will return the numeric length, but what if the strings are too large.
I'd suggest using the byteorder crate (which also works in a no-std environment):
use byteorder::{BigEndian, ReadBytesExt}; // 1.2.7 fn main() { let mut buf: &[u8] = &[0, 0, 0, 1]; let num = buf.read_u32::<BigEndian>().unwrap(); assert_eq!(1, num); }
This handles oddly-sized slices and automatically advances the buffer so you can read multiple values.
As of Rust 1.32, you can also use the from_le_bytes
/ from_be_bytes
/ from_ne_bytes
inherent methods on integers:
fn main() { let buf = [0, 0, 0, 1]; let num = u32::from_be_bytes(buf); assert_eq!(1, num); }
These methods only handle fixed-length arrays to avoid dealing with the error when not enough data is present. If you have a slice, you will need to convert it into an array.
See also:
I'd like to give this answer here to commit the following additional details:
no_std
environment.Without external crates, the following methods are suitable to convert from slices to integer even for no_std
build starting from Rust 1.32:
try_into
+ from_be_bytes
)use core::convert::TryInto; let src = [1, 2, 3, 4, 5, 6, 7]; // 0x03040506 u32::from_be_bytes(src[2..6].try_into().unwrap());
use core::conver::TryInto
is for no_std
build. And the way to use the standard crate is the following: use std::convert::TryInto;
.
(And about endians it has been already answered, but let me keep it here in one place: from_le_bytes, from_be_bytes, and from_ne_bytes - use them depending on how integer is represented in memory).
clone_from_slice
+ from_be_bytes
)let src = [1, 2, 3, 4, 5, 6, 7]; let mut dst = [0u8; 4]; dst.clone_from_slice(&src[2..6]); // 0x03040506 u32::from_be_bytes(dst);
In both cases integer will be equal to 0x03040506
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With