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

时间:2019-10-11 16:26:46

标签: rust

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

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

#![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 on github)每晚使用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 book的许多部分,还看了其他数十篇文章,似乎弄清楚了语法。

问题:如何更改bytes声明以修复上面说明错误的示例?而且,如果不支持或不习惯这种做法,哪种方法可行?

1 个答案:

答案 0 :(得分:2)

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

我的建议是对字节字段使用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);

}

关于使用动态大小类型的here,您可以得到更多的了解。

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