Могу ли я получить длину массива Rust только с типом, а не с конкретной переменной? - PullRequest
0 голосов
/ 18 сентября 2018

Я хочу переписать следующий код C ++ в Rust:

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

Как я могу получить это значение постоянной длины без конкретной переменной?

В качестве мотивации, хотя это может показаться тривиальным, я хочу напечатать количество элементов массива без объявления переменной. Я знаю, что могу использовать постоянное значение или объявить фиктивную переменную, но мне интересно, как Rust может сохранить код C ++.

Я допускаю без конкретной переменной не ясно. Я хочу достичь вышеупомянутой функции C ++, но это объяснение может вводить в заблуждение. Мне любопытно, есть ли способ получить тип элемента массива.

Ответы [ 5 ]

0 голосов
/ 18 сентября 2018

Просто для удовольствия:

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 элементов и будет вызывать панику, если тип элемента массива имеет нулевой размер. Кроме того, вы можете использовать другие вещи, кроме типов массивов, и я понятия не имею, что он будет делать.

0 голосов
/ 18 сентября 2018

Я понимаю, что вы хотите получить длину массива только из информации о типе.Rust не имеет встроенных типов PI (aka const generics ).Это означает, что универсальные параметры типа , а не (например, целое число для длины массива) в настоящее время не поддерживаются языком.

Существует проблема, отслеживающая этот искорее всего, мы увидим его поддержку в будущем, но не в ближайшем будущем.

Если вам нужно, вы можете обойти это ограничение, применив черту для каждого типа:

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 также помогают обеспечить некоторую поддержку обобщенных констант в существующем языке.

0 голосов
/ 18 сентября 2018

Вы можете использовать mem::size_of:

let storage_len = std::mem::size_of::<[i32; 3]>() / std::mem::size_of::<i32>();
0 голосов
/ 18 сентября 2018

Массивы приводят к слайсам , поэтому любой метод, доступный для слайсов, также доступен для массивов.Как len():

let v = [0u32; 128];
assert_eq!(128, v.len());
0 голосов
/ 18 сентября 2018

В 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>());
}

площадка

Однако для этого необходимо знать тип элементов, хранящихся в массиве. Я не знаю способа получить это без создания экземпляра переменной.

...