arraysrustdependent-typeconstant-expression

Can I get a Rust array's length with only a type, not a concrete variable?


I want to rewrite the following C++ code into Rust:

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

How can I get that constant length value without a concrete variable?

As motivation, although it may seem trivial, I want to print the array's element count without declaring a variable. I know I could use a constant value or declare a dummy variable, but I wonder how Rust can preserve C++ code.

I admit without a concrete variable is not clear. I want to achieve the above C++ feature, but this explanation can be misleading. I'm curious if there is any way to get the array's element type.


Solution

  • Rust now has support for const generics. I left the old answer so people have an idea why someone might have asked this in the first place.

    New Answer since Rust 1.51:

    pub trait Length {
        const LEN: usize;
    }
    
    impl<T, const LENGTH: usize> Length for [T; LENGTH] {
        const LEN: usize = LENGTH;
    }
    
    fn main() {
        println!("{}", <[String; 1]>::LEN);
    }
    
    

    Old Answer:

    I understand that you want to retrieve the array length from the type information alone. Rust does not have built-in PI types (a.k.a. const generics). This means generic parameters which are not types (like an integer for an array length) are currently not supported by the language.

    There is an issue tracking this and we are likely to see support for it in the future, though not the near future.

    If you have to, you can work around that limitation by implementing a trait for each type:

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

    Macros can help prevent repetitive typing:

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

    Crates like typenum also help to provide some support for const generics within the existing language.