如何在Rust编译时确定数组的大小?

问题描述 投票:4回答:1

我有一个C库,它期望能明确定义字符串长度的字符串类型:

#[repr(C)]
pub struct FFIStr {
    len: usize,
    data: *const u8,
}

因为此类型用作静态,所以我想使用const函数或宏(而不是手动设置len)来安全地声明它。

我的第一次尝试是使用宏和len(),但是尚无法获得length of a slice as a const fn in stable

macro_rules! ffi_string {
    ($x:expr) => {
        FFIStr { len: $x.len(), data: $x as *const u8 }
    };
}

#[no_mangle]
pub static mut HELLO_WORLD: FFIStr = ffi_string!(b"Hello, world!");

error: core::slice::<impl [T]>::len` is not yet stable as a const function

我的第二次尝试是使用std::mem::size_of<T>,但似乎没有一种方法可以使用泛型来获得静态数组的类型:

std::mem::size_of<T>

尽管这很有效(令人惊讶的是,它很容易被滥用,因为它会疯狂地将您传递给const fn ffi_string<T>(s: &'static T) -> FFIStr { FFIStr { len: ::std::mem::size_of::<T>(), data: s as *const _ as *const _ } } #[no_mangle] pub static mut HELLO_WORLD: FFIStr = ffi_string(b"Hello, world!"); 的所有内容强制转换。

似乎*const u8将是一个不错的解决方案,但它们目前不稳定:

const_generics

const fn ffi_string<const SIZE: usize>(s: &'static [u8; SIZE]) -> FFIStr { FFIStr { len: SIZE, data: s as *const u8 } } #[no_mangle] pub static mut X: FFIStr = ffi_string(b"Hello, world!");

在编译时是否有更好的方法来确定静态数组的大小?

arrays static rust compile-time-constant
1个回答
2
投票

直到error[E0658]: const generics are unstableconst_generics稳定下来,这是基于通用C const_slice_len宏的一种方法:

ARRAY_SIZE

[它使用const泛型函数macro_rules! array_size { ($x:expr) => ( (size_of_val($x) / size_of_val(&$x[0])) ) } const fn size_of_val<T>(_: &T) -> usize { std::mem::size_of::<T>() } fn main() { assert_eq!(3, array_size!(&[1, 2, 3])); assert_eq!(13, array_size!(b"Hello, world!")); } 确定类型,从而确定通过引用传递的值的大小(内置size_of_val<T>不是const)。

Note:这不适用于大小为0的数组。可以通过使用std::mem::size_of_val来解决此问题,但代价是错误地接受了非数组类型(例如std::mem::size_of_val)。

© www.soinside.com 2019 - 2024. All rights reserved.