Я хотел бы создать структуру, имеющую байтовый массив, где конкретный экземпляр может иметь разные размеры в зависимости от создания структуры, известной во время компиляции.
Я создал надуманный примериспользуя структуру, которая имеет байтовое представление числа с плавающей запятой с отдельным полем типа. Ниже приведена рабочая реализация:
#![feature(float_to_from_bytes)]
#[derive(Debug)]
enum TypeMarker {
NUMBER = 0x00, // f64
// BOOLEAN: u8 = 0x01, // bool
// STRING: u8 = 0x02, // UTF-8 string
}
#[derive(Debug)]
struct Value {
t: TypeMarker,
bytes: [u8; 8]
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value {
t: TypeMarker::NUMBER,
bytes: v.to_be_bytes()
}
}
}
fn main() {
let num = 4.0;
println!("num = {:?}", num);
let v1 = Value::from(4.0);
println!("Value::from(4.0) = {:?}", v1);
let v2:Value = num.into();
println!("num.into() = {:?}", v2);
}
Этот рабочий пример (см. Также repo на github ) использует ночной ржавчину.
Запуск примера ... cargo +nightly run --example into
дает ожидаемый результат:
num = 4.0
Value::from(4.0) = Value { t: NUMBER, bytes: [64, 16, 0, 0, 0, 0, 0, 0] }
num.into() = Value { t: NUMBER, bytes: [64, 16, 0, 0, 0, 0, 0, 0] }
Однако я хочу поддерживать различные типы чиселгде размер известен во время компиляции. Чтобы проиллюстрировать этот вопрос, в приведенном ниже примере добавляется impl From<i32>
(длина которого 4 байта):
#![feature(float_to_from_bytes)]
#[derive(Debug)]
enum TypeMarker {
NUMBER = 0x00, // f64
// BOOLEAN: u8 = 0x01, // bool
// STRING: u8 = 0x02, // UTF-8 string
}
#[derive(Debug)]
struct Value {
t: TypeMarker,
bytes: [u8; 8]
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value {
t: TypeMarker::NUMBER,
bytes: v.to_be_bytes()
}
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value {
t: TypeMarker::NUMBER,
bytes: v.to_be_bytes()
}
}
}
fn main() {
let num = 4.0;
println!("num = {:?}", num);
let v1 = Value::from(4.0);
println!("Value::from(4.0) = {:?}", v1);
let v2:Value = num.into();
println!("num.into() = {:?}", v2);
}
это приводит к следующей ошибке
error[E0308]: mismatched types
--> examples/into.rs:33:20
|
33 | bytes: v.to_be_bytes()
| ^^^^^^^^^^^^^^^ expected an array with a fixed size of 8 elements, found one with 4 elements
|
= note: expected type `[u8; 8]`
found type `[u8; 4]`
Я хотел бы объявить Value
структура, так что он может быть создан с массивами байтов переменного размера (где размер известен во время компиляции).
я пробовал:
struct Value {
t: TypeMarker,
bytes: [u8; usize]
}
error[E0423]: expected value, found builtin type `usize`
--> examples/into.rs:17:17
|
17 | bytes: [u8; usize]
| ^^^^^ not a value
error[E0277]: arrays only have std trait implementations for lengths 0..=32
--> examples/into.rs:17:5
|
17 | bytes: [u8; usize]
| ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[u8; _]`
|
= note: required because of the requirements on the impl of `std::fmt::Debug` for `[u8; _]`
= note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u8; _]`
= note: required for the cast to the object type `dyn std::fmt::Debug`
ИтакЯ попытался:
struct Value {
t: TypeMarker,
bytes: [u8; _]
}
, который тоже не работал:
error: expected expression, found reserved identifier `_`
--> examples/into.rs:17:17
|
17 | bytes: [u8; _]
| ^ expected expression
error: aborting due to previous error
Кажется, это должно быть возможно, и я думаю, что однажды прочитал синтаксис для этого, но яЯ перечитал многие разделы Rust book , просмотрел десятки других постов и не могу понять синтаксис.
Вопрос: Как изменить объявление bytes
, чтобы исправить приведенный выше пример, иллюстрирующий ошибку? И, если это не поддерживается или не является идиоматическим, какой подход будет работать?