39
votes

I want to create array like this:

let arr = [0; length];

Where length is a usize. But I get this error

E0307
The length of an array is part of its type. For this reason, this length 
must be a compile-time constant.

Is it possible to create array with dynamic length? I want an array, not a Vec.

3
I don't think that's possible. Why do you not want to use a Vec? - fjh
Maybe you should describe which qualities of a Vec you think are lacking that an array satisfies. - Brian Cain
Or maybe use Slice, it is similar to Array but size of a Slice does not have to be known at compile time. - Akavall
I have some functions that accepts references to array, so i need array for it. - Dima Kudosh
@DimaKudosh, are you sure they accept references to an array, not slices (e.g. &[u32])? If they are in fact slices, then Vec<T> is freely convertible to &[T], usually with just &: let v: Vec<u32> = ...; let s: &[u32] = &v. And if they do in fact accept references to an array, then how dynamically sized arrays would help you? Rust does not have type-level integers, so the size of the array would be necessarily constant in this case. - Vladimir Matveev

3 Answers

59
votes

Is it possible to create array with dynamic length?

No. By definition, arrays have a length defined at compile time. A variable (because it can vary) is not known at compile time. The compiler would not know how much space to allocate on the stack to provide storage for the array.

You will need to use a Vec:

let arr = vec![0; length];

See also:

8
votes

You can create your own HeapArray. It's not that complicated if you read alloc's docs:

use std::alloc::{alloc, dealloc, Layout};
pub struct HeapArray<T> {
    ptr: *mut T,
    len: usize,
}

impl<T> HeapArray<T> {
    pub fn new(len: usize) -> Self {
        let ptr = unsafe {
            let layout = Layout::from_size_align_unchecked(len, std::mem::size_of::<T>());
            alloc(layout) as *mut T
        };
        Self { ptr, len }
    }
    pub fn get(&self, idx: usize) -> Option<&T> {
        if idx < self.len {
            unsafe { Some(&*(self.ptr.add(idx))) }
        } else {
            None
        }
    }
    pub fn get_mut(&self, idx: usize) -> Option<&mut T> {
        if idx < self.len {
            unsafe { Some(&mut *(self.ptr.add(idx))) }
        } else {
            None
        }
    }
    pub fn len(&self) -> usize {
        self.len
    }
}


impl<T> Drop for HeapArray<T> {
    fn drop(&mut self) {
        unsafe {
            dealloc(
                self.ptr as *mut u8,
                Layout::from_size_align_unchecked(self.len, std::mem::size_of::<T>()),
            )
        };
    }
}

impl<T> std::ops::Index<usize> for HeapArray<T> {
    type Output = T;
    fn index(&self, index: usize) -> &Self::Output {
        self.get(index).unwrap()
    }
}
impl<T> std::ops::IndexMut<usize> for HeapArray<T> {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.get_mut(index).unwrap()
    }
}

You may also add methods like as_slice, get_unchecked, etc.

6
votes

This should be possible after variable length arrays (VLA) are implemented.