我可以只使用类型而不是具体变量来获取Rust数组的长度吗?

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

我想将以下C ++代码重写为Rust:

using storage = array<int, 3>;
const size_t storage_len = sizeof(storage) / sizeof(storage::value_type);

如何在没有具体变量的情况下获得恒定长度值?

作为动机,尽管看起来似乎微不足道,但我想在不声明变量的情况下打印数组的元素数。我知道我可以使用常量值或声明一个虚拟变量,但我想知道Rust如何保存C ++代码。

我承认没有具体变量尚不清楚。我想实现上述C ++功能,但这种解释可能会产生误导。我很好奇是否有任何方法可以获得数组的元素类型。

arrays rust dependent-type constant-expression
5个回答
7
投票

我知道你只想从类型信息中检索数组长度。 Rust没有内置的PI类型(a.k.a. const generics)。这意味着该语言当前不支持非类型的通用参数(如数组长度的整数)。

an issue tracking this,我们可能会在未来看到它的支持,虽然不是在不久的将来。

如果必须,您可以通过为每种类型实现特征来解决该限制:

trait GetLength {
    fn len() -> usize;
}

impl<T> GetLength for [T; 0] {
    fn len() -> usize {
        0
    }
}

impl<T> GetLength for [T; 1] {
    fn len() -> usize {
        1
    }
}

// ...

fn main() {
    println!("{}", <[String; 1]>::len());
}

宏可以帮助防止重复输入:

trait GetLength {
    fn len() -> usize;
}

macro_rules! impl_get_length {
    ($v:expr) => {
        impl<T> GetLength for [T; $v] {
            fn len() -> usize {
                $v
            }
        }
    };
}

impl_get_length!{ 0 }
impl_get_length!{ 1 }

// ...

fn main() {
    println!("{}", <[String; 1]>::len());
}

typenum这样的包装箱也有助于为现有语言中的const泛型提供一些支持。


5
投票

在Rust中,您可以使用std::mem::size_of获取类型的大小,因此您可以使用与C ++相同的方式获取数组类型的长度:

use std::mem::size_of;

type Storage = [i32; 3];

fn main() {
    println!("Length: {}", size_of::<Storage>() / size_of::<i32>());
}

playground

但是,这需要知道存储在数组中的项目类型。我不知道如何在不实例化变量的情况下获得它。


3
投票

纯娱乐:

use std::mem;
use std::ops::Deref;

fn main() {
    assert_eq!(5, num_elems::<[i32; 5]>());
}

fn num_elems<T>() -> usize 
where 
    T: 'static, 
    &'static T: IntoIterator,
    <&'static T as IntoIterator>::Item: Deref,
    <<&'static T as IntoIterator>::Item as Deref>::Target: Sized,
{
    fn inner<S, I>() -> usize 
    where 
        I: Deref,
        <I as Deref>::Target: Sized,
    { 
        mem::size_of::<S>() / mem::size_of::<I::Target>()
    }

    inner::<T, <&'static T as IntoIterator>::Item>()
}

这适用于最多32个元素的任何数组,如果数组元素类型为零,则会出现混乱。此外,除了数组类型之外,您还可以使用其他内容,我不知道它会做什么。


2
投票

你可以使用mem::size_of

let storage_len = std::mem::size_of::<[i32; 3]>() / std::mem::size_of::<i32>();

-1
投票

Arrays强制使用slices,因此切片上可用的任何方法也可用于阵列。像len()

let v = [0u32; 128];
assert_eq!(128, v.len());
© www.soinside.com 2019 - 2024. All rights reserved.