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

标签 arrays static rust compile-time-constant

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

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

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

我的第一次尝试是使用宏和 len() , 然而在 versions before 1.39.0 , 不可能得到 length of a slice as a const fn :

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> , 但除了使用泛型之外,似乎没有其他方法可以获取静态数组的类型:

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!");

error[E0658]: const generics are unstable

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

最佳答案

在 Rust 1.39.0 中 [T]::len stabilised as a const function ,现在让这个直截了当:

const ARRAY: [i32; 3] = [1, 2, 3];
const ARRAY_SIZE: usize = ARRAY.len();

fn main() {
    assert_eq!(3, ARRAY_SIZE);
}

在 Rust 的早期版本中,这是一种基于通用 C ARRAY_SIZE 的方法宏观:

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

它使用了一个 const 泛型函数 size_of_val<T>确定类型,从而确定通过引用传递的值的大小(内置 std::mem::size_of_val 不是 const)。

注意:这不适用于大小为 0 的数组。这可以通过使用 size_of_val($x) / size_of_val(unsafe { &*$x.as_ptr() }) 来解决。以错误地接受非数组类型为代价(例如 &String )。

关于arrays - 在 Rust 中如何在编译时确定数组的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58576850/

相关文章:

Java 嵌套循环检查数组中的元素是否匹配

arrays - 如何将 IMPORTRANGE() 数组转换为字符串,以便与 QUERY() 一起使用?

java - 在代码的静态分析中,影子到底是什么?

rust - 循环中看似不一致的借用检查器行为

python - 搜索一个数组中的特定元素并复制另一数组中的整个相应行

arrays - 仅在索引存在时编辑索引

ios - 静态变量为零 - Objective C

c++ - 为什么不同 TU 中的 `static` 函数不会破坏 ODR?

rust SQLx: "expected enum ` std::option::Option`"在查询中但不在类似查询中

rust - 这个元素 Rust 标记为 "dead code"是必要的吗?