Skip to content
CryoCryo home
Stdlibcollections

array

import std::collections::array; — in the prelude · source

Array<T, A>

type struct Array<T, A = GlobalAlloc> {
    ptr:      T*;
    length:   u64;
    capacity: u64;
    alloc:    A;

    static new() -> Array<T, GlobalAlloc>;
    static new_in(alloc: A) -> Array<T, A>;
    static with_capacity(capacity: u64) -> Array<T, GlobalAlloc>;
    static with_capacity_in(capacity: u64, alloc: A) -> Array<T, A>;
    static try_with_capacity_in(capacity: u64, alloc: A) -> Result<Array<T, A>, AllocError>;
    length(&this) -> u64;
    capacity(&this) -> u64;
    is_empty(&this) -> boolean;
    get(&this, index: u64) -> Option<T>
    where T: Copy;
    get_ref(&this, index: u64) -> Option<T*>;
    as_ptr(&this) -> T*;
    as_slice(&this) -> Slice<T>;
    iter(&this) -> implement Iterator<T>
    where T: Copy;
    iter_ref(&this) -> implement Iterator<T*>;
    push(mut &this, value: T) -> void;
    try_push(mut &this, value: T) -> Result<(), AllocError>;
    pop(mut &this) -> Option<T>;
    set(mut &this, index: u64, value: T) -> void
    where T: Drop;
    swap_remove(mut &this, index: u64) -> T;
    first(&this) -> Option<T*>;
    last(&this) -> Option<T*>;
    index_of(&this, value: &T) -> Option<u64>
    where T: Eq;
    contains(&this, value: &T) -> boolean
    where T: Eq;
    reverse(mut &this) -> void;
    insert(mut &this, index: u64, value: T) -> void;
    remove(mut &this, index: u64) -> T;
    truncate(mut &this, new_length: u64) -> void
    where T: Drop;
    clear(mut &this) -> void
    where T: Drop;
    sort(mut &this) -> void
    where T: Ord;
    sort_by(mut &this, less: (&T, &T) -> boolean) -> void;
    append(mut &this, source: Slice<T>) -> void
    where T: Copy;
    try_append(mut &this, source: Slice<T>) -> Result<(), AllocError>
    where T: Copy;
    resize(mut &this, new_length: u64, value: T) -> void
    where T: Copy + Drop;
    try_resize(mut &this, new_length: u64, value: T) -> Result<(), AllocError>
    where T: Copy + Drop;
    reserve(mut &this, additional: u64) -> Result<(), AllocError>;
    reserve_exact(mut &this, additional: u64) -> Result<(), AllocError>;
    shrink_to_fit(mut &this) -> void;
    resize_storage(mut &this, new_capacity: u64) -> Result<(), AllocError>;
}
function from_iter<I, T>(it: I) -> Array<T>
where I: Iterator<T>;

A growable, heap-backed, contiguous sequence. T[] desugars to Array<T>, which is why it is in the prelude. Push and pop at the end are amortized O(1); indexed access is O(1). Growth doubles capacity, starting at 4. The first three fields are laid out to match the T[] fat pointer the compiler emits, so a field declared string[] and an Array<string>::new() agree on every byte offset.

Algorithms that do not need ownership should take a Slice<T> — call as_slice() at the boundary and write the algorithm once.

mut names: Array<String> = Array<String>::new();
names.push(String::from("ada"));
names.push(String::from("grace"));

for (n in names.iter_ref()) {
    println(f"{*n}");
}

Constructing

new and with_capacity are backed by GlobalAlloc; the _in forms take your allocator. with_capacity panics on allocation failure — try_with_capacity_in is the recoverable form.

The free function from_iter collects an iterator into a fresh array:

mut squares: Array<i32> = from_iter((0..10).map(square));

It is a free function rather than an Iterator::collect default for a specific reason: a non-self-returning trait default gets cloned into every Iterator impl, including the by-reference cursor over Array<T> — whose clone would instantiate Array<T>, then Array<T*>, then Array<T**>, diverging until it ran out of memory. As a free function only concrete call sites instantiate it.

Reading

  • get is a bounds-checked read by value and needs T: Copy; get_ref is the bounds-checked borrow and is sound for every T.
  • first / last borrow, and return None when empty.
  • index_of and contains are linear scans over T: Eq.

Every pointer, slice, and iterator handed out here is invalidated by any method that may reallocate — push, insert, reserve, shrink_to_fit.

Iterating

  • iter() (where T: Copy) yields each element by value.
  • iter_ref() yields T* and is sound for every T. This is how you walk an Array<String> or Array<Box<...>> without cloning.
  • iter_ref().copied() (where T: Copy) and iter_ref().cloned() (where T: Clone) turn the borrowing cursor back into a by-value one.

Modifying

MethodNotes
push / try_pushAppend. try_push returns Result<(), AllocError> instead of panicking.
popOption<T> from the end.
set(index, value)Overwrite in place. The previous occupant is dropped first — a raw ptr[i] = v store would leak it. Panics out of range.
insert(index, value)Shifts later elements right. index == length appends; panics beyond that.
remove(index)Returns T, shifting later elements left — O(n), order preserved.
swap_remove(index)Returns T in O(1) by swapping in the last element. Does not preserve order.
truncate(new_length)Drops everything past new_length; no-op if already shorter. Keeps capacity.
clear()Drops every element and resets the length to zero. Keeps capacity — follow with shrink_to_fit to release it.
reverse()In place. Sound for owning T.
append(source)Bulk memcpy of a Slice<T>. try_append reserves up front, so a partial copy is impossible.
resize(new_length, value)Sets the length exactly, filling new slots with value. try_resize is all-or-nothing.
reserve / reserve_exactResult<(), AllocError>.
shrink_to_fit()Return unused capacity.

resize is how you build a fixed-size read buffer. An array only exposes [0, length), so with_capacity alone leaves nothing to read into.

Sorting

sort() (where T: Ord) sorts ascending in place using a hybrid in-place quicksort: median-of-three pivot above a cutoff of 16 elements, insertion sort below it. O(n log n) average, no allocation. Two caveats: it is not stable, and the worst case is O(n²) — v1.0 has no introsort fallback. Owning elements are moved with mem::swap, so the drop obligation stays intact.

sort_by(less) takes your own strict-weak-ordering predicate. It must be a function pointer; non-capturing lambdas convert implicitly, and a capturing closure in method position is rejected (E0458) in v1.0. Capture by indirection, or pull the sort into a free function.

Trait implementations

implement<T, A> trait Drop for struct Array<T, A>
where T: Drop, A: Allocator

implement<T> trait Clone for struct Array<T, GlobalAlloc>
where T: Clone

implement<T> trait Default for struct Array<T, GlobalAlloc>

implement<T, A> trait Eq for struct Array<T, A>
where T: Eq, A: Allocator

implement<T, A> trait Hash for struct Array<T, A>
where T: Hash, A: Allocator

implement<T, A> trait Display for struct Array<T, A>
where T: Display, A: Allocator   // std::fmt::display

implement<T, A> trait Debug for struct Array<T, A>
where T: Debug, A: Allocator   // std::fmt::display

Clone is a deep copy into a fresh buffer sized to length. Default is a fresh empty array that allocates nothing. Eq is equal length and equal elements in order. Hash folds the length first, so [1, 2] and [1, 2, 0] differ. Display renders [a, b, c] and Debug the same with each element in Debug form; both live in fmt.