How do I convert two u8 primitives into a u16 primitive?
You can multiply the first element to move it to the higher byte, then add the second element. It just needs extra casting:
let a: u8 = 1;
let b: u8 = 2;
let c: u16 = (a as u16 * 256) + b as u16;
println!("c: {}", c); // c: 258
If you actually had two distinct u8
s, the conventional solution involves bitwise manipulation, specifically shifting and bitwise OR. This requires zero heap allocation and is very efficient:
let number = ((vector[0] as u16) << 8) | vector[1] as u16;
And a graphical explanation:
A0 B0
+--------+ +--------+
|XXXXXXXX| |YYYYYYYY|
+-------++ +-------++
| |
A1 = A0 as u16 | B1 = B0 as u16 |
+---------------v+ +---------------v+
|00000000XXXXXXXX| |00000000YYYYYYYY|
+---------------++ +---------------++
| |
A2 = A1 << 8 | |
+---------------v+ |
|XXXXXXXX00000000| |
+---------------++ |
| +--+ |
+-------------->OR<--+
+-++
|
V = A2 | B1 |
+----------+----v+
|XXXXXXXXYYYYYYYY|
+----------------+
However, you are really looking at your problem too narrowly. You don't have two u8
, you have a &[u8]
.
In this case, use the byteorder crate:
use byteorder::{ByteOrder, LittleEndian}; // 1.3.4
fn main() {
let data = [1, 16];
let v = LittleEndian::read_u16(&data);
println!("{}", v);
}
This shows its power when you want to handle reading through the buffer:
use byteorder::{BigEndian, LittleEndian, ReadBytesExt}; // 1.3.4
fn main() {
let data = [1, 16, 1, 2];
let mut current = &data[..];
let v1 = current.read_u16::<LittleEndian>();
let v2 = current.read_u16::<BigEndian>();
println!("{:?}, {:?}", v1, v2); // Ok(4097), Ok(258)
}
As you can see, you need to be conscious of the endianness of your input data.
You could also get a fixed-size array from your slice and then use u16::from_le_bytes
. If you had a &[u8]
and wanted to get a Vec<u16>
, you can iterate over appropriately-sized slices using chunks_exact
(or array_chunks
).
See also:
- How do you set, clear and toggle a single bit in Rust?
- Temporarily transmute [u8] to [u16]
- How do I convert a Vec<T> to a Vec<U> without copying the vector?
Free code review on your original post:
There's no need to use
to_vec
here, usevec!
instead.There's no need to specify the vast majority of the types.
let vector = [1u8, 16].to_vec(); let vector0 = format!("{:02x}", vector[0]); let vector1 = format!("{:02x}", vector[1]); let mut vector_combined = String::new(); vector_combined = vector_combined + &vector0.clone(); vector_combined = vector_combined + &vector1.clone(); let number = u16::from_str_radix(&vector_combined.to_string(), 16).unwrap();
There's no need to clone the strings before taking a reference to them when adding.
There's no need to convert the
String
to... anotherString
infrom_str_radix
.let vector0 = format!("{:02x}", vector[0]); let vector1 = format!("{:02x}", vector[1]); let mut vector_combined = String::new(); vector_combined = vector_combined + &vector0; vector_combined = vector_combined + &vector1; let number = u16::from_str_radix(&vector_combined, 16).unwrap();
There's no need to create an empty
String
to append to, just usevector0
let vector0 = format!("{:02x}", vector[0]); let vector1 = format!("{:02x}", vector[1]); let vector_combined = vector0 + &vector1; let number = u16::from_str_radix(&vector_combined, 16).unwrap();
There's no need to create two strings at all, one will do:
let vector_combined = format!("{:02x}{:02x}", vector[0], vector[1]); let number = u16::from_str_radix(&vector_combined, 16).unwrap();
Of course, this still isn't the right solution, but it's better.