声明具有变量大小的数组类型的语法(编译时已知)?



>我想创建一个具有字节数组的结构,其中特定实例可能根据编译时已知的结构的创建而具有不同的大小。

我创建了一个人为的示例,该结构具有浮点数的字节表示形式,具有单独的类型字段。工作实现如下:

#![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);
}

这个工作示例(另请参阅 github 上的 repo(每晚使用 rust。

运行示例...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 书的许多部分并查看了数十个其他帖子,似乎无法完全弄清楚语法。

问题:如何更改bytes声明以修复上面说明错误的示例? 而且,如果不支持或不惯用,什么方法会起作用?

数组是在堆栈上分配的,因此使用堆创建具有此属性的结构会容易得多。

我的建议是使用Vec作为字节字段

#[derive(Debug)]
struct Value {
t: TypeMarker,
bytes: Vec<u8>
}

或者使用盒装数组:

#![feature(float_to_from_bytes)]
use std::boxed::Box;
#[derive(Debug)]
enum TypeMarker {
NUMBER = 0x00,  // f64
// BOOLEAN: u8 = 0x01, // bool
// STRING: u8 = 0x02,  // UTF-8 string
}
#[derive(Debug)]
struct Value {
t: TypeMarker,
bytes: Box<[u8]>,
}
impl From<f64> for Value{
fn from(v: f64) -> Self {
Value {
t: TypeMarker::NUMBER,
bytes: Box::new(v.to_be_bytes()),
}
}
}
impl From<i32> for Value{
fn from(v: i32) -> Self {
Value {
t: TypeMarker::NUMBER,
bytes: Box::new(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);
}

您可以在此处获得有关使用动态大小类型的其他阅读。

希望这有帮助!祝你好运!

最新更新