Skip to content
CryoCryo home
Stdlibcollections

array

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

Types

Array<T, A>

type struct Array<T, A = GlobalAlloc> where A: Allocator {
    ptr:      T*;
    length:   i64;
    capacity: i64;
    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) -> i64;
    capacity(&this) -> i64;
    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;
    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;
    clear(mut &this) -> void;

    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;

    try_resize(mut &this, new_length: u64, value: T) -> Result<(), AllocError>
    where T: Copy;

    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: i64) -> Result<(), AllocError>;
}

A growable, heap-backed, contiguous sequence. [T] is a spelling of 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}");
}

Properties

PropertyType
ptrT*
lengthi64
capacityi64
allocA

Constructors

static new() -> Array<T, GlobalAlloc>;

Empty array backed by GlobalAlloc.

static new_in(alloc: A) -> Array<T, A>;

Empty array with a caller-supplied allocator.

static with_capacity(capacity: u64) -> Array<T, GlobalAlloc>;

Preallocate room for capacity elements. Panics on allocation failure; use try_with_capacity_in to recover.

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>;

Methods

length(&this) -> i64;
capacity(&this) -> i64;
is_empty(&this) -> boolean;
get(&this, index: u64) -> Option<T> where T: Copy;

Bounds-checked read by value. Gated on T: Copy: the result is an independent bitwise duplicate while the array retains ownership of the stored element, so handing back a copy is only sound when T carries no Drop obligation. For owning T, borrow in place with get_ref (or move an element out with swap_remove/pop).

get_ref(&this, index: u64) -> Option<T*>;

Bounds-checked borrow. Returns a pointer to the element in place; the array keeps ownership, so this is sound for every T (Copy or owning). The pointer is invalidated by any reallocating method (push, reserve, shrink_to_fit).

as_ptr(&this) -> T*;

Raw pointer. Invalidated by any method that may reallocate (push, reserve, shrink_to_fit).

as_slice(&this) -> Slice<T>;

Borrow the initialized prefix. Slice is invalidated by any reallocating method.

iter(&this) -> implement Iterator<T> where T: Copy;

Iterate over the elements in order, yielding each by value (bitwise copy). Gated on T: Copy for the same reason as get: a yielded owning value would alias storage the array still owns. For owning T, walk by index with length() + get_ref. The iterator is invalidated by any reallocating method on the array (push, reserve, shrink_to_fit).

iter_ref(&this) -> implement Iterator<T*>;

Iterate by shared borrow, yielding T* for each element in order. Unlike iter, this is sound for every T (Copy or owning) because it hands out borrows, never copies. The pointers are invalidated by any reallocating method (push, reserve, insert, shrink_to_fit). This is the way to walk an Array<String> / Array<Box<...>> without cloning.

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;

Overwrite the element at index, taking ownership of value. The previous occupant is released in place before the slot is reused: a raw slot store (this.ptr[index] = value) does NOT drop the destination, so for owning T (String, Box<T>, ...) the old element's resources would otherwise leak. Panics on out-of-range.

swap_remove(mut &this, index: u64) -> T;

Remove at index by swapping in the last element. O(1) but doesn't preserve order. Panics on out-of-range.

first(&this) -> Option<T*>;

First element by shared borrow, or None if empty. Sound for every T (the array keeps ownership). Invalidated by any reallocating method.

last(&this) -> Option<T*>;

Last element by shared borrow, or None if empty.

index_of(&this, value: &T) -> Option<u64> where T: Eq;

Index of the first element equal to value, or None. Linear scan; T: Eq.

contains(&this, value: &T) -> boolean where T: Eq;

True if some element equals value. T: Eq.

reverse(mut &this) -> void;

Reverse the elements in place. Sound for owning T: each pair is exchanged with a three-step move (identical to mem::swap's body, inlined here so the method stays self-contained - see note below).

insert(mut &this, index: u64, value: T) -> void;

Insert value at index, shifting later elements right by one. index == length appends. Panics if index > length. Panics on allocation failure; use the Result-returning forms for recovery via try_push if you need fallibility on the common (append) path.

remove(mut &this, index: u64) -> T;

Remove and return the element at index, shifting later elements left by one to preserve order (O(n)). Panics if out of range. For O(1) removal when order doesn't matter, use swap_remove.

truncate(mut &this, new_length: u64) -> void;

Shorten to at most new_length, releasing the truncated elements in place. A no-op if new_length >= length. Keeps capacity.

clear(mut &this) -> void;

Release every initialized element (the [0, length) prefix) in place, then reset the length to zero while keeping the backing capacity. Mirrors drop's element teardown so Array<String>, Array<Box<...>>, and similar owning shapes don't leak their contents. Follow with shrink_to_fit to release the capacity, or drop when the array itself goes away.

sort(mut &this) -> void where T: Ord;

Sort the array in place, ascending, by T::compare.

sort_by(mut &this, less: (&T, &T) -> boolean) -> void;

Sort in place using a user-supplied "less-than" predicate. Returns no value; mutates the array. Same complexity and stability as sort(). The predicate must impose a strict weak ordering (irreflexive, transitive, with the implied equivalence being transitive) or the result is unspecified.

append(mut &this, source: Slice<T>) -> void where T: Copy;

Append every element of source to the end of this array. Panics on allocation failure; use try_append to recover.

try_append(mut &this, source: Slice<T>) -> Result<(), AllocError> where T: Copy;

Fallible bulk append. Reserves space for all elements first so partial copies are impossible; either all elements are appended or none are. Gated on T: Copy (see append): the append is a bitwise memcpy out of the borrowed source.

resize(mut &this, new_length: u64, value: T) -> void where T: Copy;

Set the length to exactly new_length, filling any new slots with value. Shrinking drops the elements above new_length, exactly as truncate does; growing leaves every slot initialized, so the whole [0, new_length) range is readable afterwards.

try_resize(mut &this, new_length: u64, value: T) -> Result<(), AllocError> where T: Copy;

Fallible resize. Reserves the whole growth up front, so the array is either resized or left exactly as it was - never partially grown.

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: i64) -> Result<(), AllocError>;

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. To build an array from an iterator, use the free function from_iter.

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

push appends and pop takes from the end; try_push returns Result<(), AllocError> instead of panicking, as do reserve and reserve_exact. insert and remove shift the tail and preserve order; swap_remove is the O(1) alternative when order does not matter. set, truncate, clear, and resize all drop whatever they displace, so an Array<String> never leaks through them. clear and truncate keep the capacity — follow with shrink_to_fit to release it.

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 Index<i8, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<i16, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<i32, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<i64, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<isize, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<u8, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<u16, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<u32, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<u64, T> for struct Array<T, A> where A: Allocator
implement<T, A> trait Index<usize, T> for struct Array<T, A> where 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.

Free Functions

function from_iter<I, T>(it: I) -> Array<T> where I: Iterator<T>;

Collect every element an iterator yields into a fresh Array<T>, in order. it is consumed. T is recovered from the iterator's Iterator<T> impl, and the result element type is fixed by the expected type at the call site:

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.

Constants

const INITIAL_CAPACITY:      i64 = 4;
const SORT_INSERTION_CUTOFF: u64 = 16;