Skip to main content
Version: v1.0.0-beta.0

Slices

Experimental Feature

This feature is experimental. The documentation may be incomplete or out of date, which means it could change in future versions, potentially causing unexpected behavior or not working as expected.

Contributions Welcome: If you notice any inaccuracies or potential improvements, please consider contributing. Visit our GitHub repository to make your contributions: Contribute Here.

A slice is a dynamically-sized view into a sequence of elements. They can be resized at runtime, but because they don't own the data, they cannot be returned from a circuit. You can treat slices as arrays without a constrained size.

fn main() -> pub u32 {
let mut slice: [Field] = &[0; 2];

let mut new_slice = slice.push_back(6);
new_slice.len()
}

To write a slice literal, use a preceding ampersand as in: &[0; 2] or &[1, 2, 3].

It is important to note that slices are not references to arrays. In Noir, &[..] is more similar to an immutable, growable vector.

View the corresponding test file here.

Methods

For convenience, the STD provides some ready-to-use, common methods for slices:

push_back

Pushes a new element to the end of the slice, returning a new slice with a length one greater than the original unmodified slice.

fn push_back<T>(_self: [T], _elem: T) -> [T]

example:

fn main() -> pub Field {
let mut slice: [Field] = &[0; 2];

let mut new_slice = slice.push_back(6);
new_slice.len()
}

View the corresponding test file here.

push_front

Returns a new array with the specified element inserted at index 0. The existing elements indexes are incremented by 1.

fn push_front(_self: Self, _elem: T) -> Self

Example:

let mut new_slice: [Field] = &[];
new_slice = new_slice.push_front(20);
assert(new_slice[0] == 20); // returns true

View the corresponding test file here.

pop_front

Returns a tuple of two items, the first element of the array and the rest of the array.

fn pop_front(_self: Self) -> (T, Self)

Example:

let (first_elem, rest_of_slice) = slice.pop_front();

View the corresponding test file here.

pop_back

Returns a tuple of two items, the beginning of the array with the last element omitted and the last element.

fn pop_back(_self: Self) -> (Self, T)

Example:

let (popped_slice, last_elem) = slice.pop_back();

View the corresponding test file here.

append

Loops over a slice and adds it to the end of another.

fn append(mut self, other: Self) -> Self

Example:

let append = &[1, 2].append(&[3, 4, 5]);

insert

Inserts an element at a specified index and shifts all following elements by 1.

fn insert(_self: Self, _index: Field, _elem: T) -> Self

Example:

new_slice = rest_of_slice.insert(2, 100);
assert(new_slice[2] == 100);

View the corresponding test file here.

remove

Remove an element at a specified index, shifting all elements after it to the left, returning the altered slice and the removed element.

fn remove(_self: Self, _index: Field) -> (Self, T)

Example:

let (remove_slice, removed_elem) = slice.remove(3);

len

Returns the length of a slice

fn len(self) -> Field

Example:

fn main() {
let slice = &[42, 42];
assert(slice.len() == 2);
}

as_array

Converts this slice into an array.

Make sure to specify the size of the resulting array. Panics if the resulting array length is different than the slice's length.

fn as_array<let N: u32>(self) -> [T; N]

Example:

fn main() {
let slice = &[5, 6];

// Always specify the length of the resulting array!
let array: [Field; 2] = slice.as_array();

assert(array[0] == slice[0]);
assert(array[1] == slice[1]);
}

map

Applies a function to each element of the slice, returning a new slice containing the mapped elements.

fn map<U, Env>(self, f: fn[Env](T) -> U) -> [U]

example

let a = &[1, 2, 3];
let b = a.map(|a| a * 2); // b is now &[2, 4, 6]

fold

Applies a function to each element of the slice, returning the final accumulated value. The first parameter is the initial value.

fn fold<U, Env>(self, mut accumulator: U, f: fn[Env](U, T) -> U) -> U

This is a left fold, so the given function will be applied to the accumulator and first element of the slice, then the second, and so on. For a given call the expected result would be equivalent to:

let a1 = &[1];
let a2 = &[1, 2];
let a3 = &[1, 2, 3];

let f = |a, b| a - b;
a1.fold(10, f) //=> f(10, 1)
a2.fold(10, f) //=> f(f(10, 1), 2)
a3.fold(10, f) //=> f(f(f(10, 1), 2), 3)

example:


fn main() {
let slice = &[2, 2, 2, 2, 2];
let folded = slice.fold(0, |a, b| a + b);
assert(folded == 10);
}

reduce

Same as fold, but uses the first element as the starting element.

fn reduce<Env>(self, f: fn[Env](T, T) -> T) -> T

example:

fn main() {
let slice = &[2, 2, 2, 2, 2];
let reduced = slice.reduce(|a, b| a + b);
assert(reduced == 10);
}

filter

Returns a new slice containing only elements for which the given predicate returns true.

fn filter<Env>(self, f: fn[Env](T) -> bool) -> Self

example:

fn main() {
let slice = &[1, 2, 3, 4, 5];
let odds = slice.filter(|x| x % 2 == 1);
assert_eq(odds, &[1, 3, 5]);
}

join

Flatten each element in the slice into one value, separated by separator.

Note that although slices implement Append, join cannot be used on slice elements since nested slices are prohibited.

fn join(self, separator: T) -> T where T: Append

example:

struct Accumulator {
total: Field,
}

// "Append" two accumulators by adding them
impl Append for Accumulator {
fn empty() -> Self {
Self { total: 0 }
}

fn append(self, other: Self) -> Self {
Self { total: self.total + other.total }
}
}

fn main() {
let slice = &[1, 2, 3, 4, 5].map(|total| Accumulator { total });

let result = slice.join(Accumulator::empty());
assert_eq(result, Accumulator { total: 15 });

// We can use a non-empty separator to insert additional elements to sum:
let separator = Accumulator { total: 10 };
let result = slice.join(separator);
assert_eq(result, Accumulator { total: 55 });
}

all

Returns true if all the elements satisfy the given predicate

fn all<Env>(self, predicate: fn[Env](T) -> bool) -> bool

example:

fn main() {
let slice = &[2, 2, 2, 2, 2];
let all = slice.all(|a| a == 2);
assert(all);
}

any

Returns true if any of the elements satisfy the given predicate

fn any<Env>(self, predicate: fn[Env](T) -> bool) -> bool

example:

fn main() {
let slice = &[2, 2, 2, 2, 5];
let any = slice.any(|a| a == 5);
assert(any);
}