Functors and Monads in Rust

This was going to be a functor and monad tutorial in various programming languages using the same post structure. While working on the Rust version of the post, I came to the realization that learning exactly what they are (either in the context of category theory or Haskell) is not really useful. So I scrapped the idea and decided to do a quick showcase of some examples of the Functor and Monad patterns in the Rust standard library.

Functor

In Rust, the functor pattern resembles a generic Functor<T> with a practical implementation of the following function:

fn <, , >(: Functor<>, : ) -> Functor<>
where
    : () -> ,
{
    !()
}

In English:

If I have a Functor of T, and I have a function that turns Ts into Us, the function fmap gives me a Functor of U.

Example 1: Option

Option with Option::map is a functor.

impl<> <> {
  pub fn <, >(, : ) -> <>
    where
        : () -> ,
    {
        match  {
            () => (()),
             => ,
        }
    }
}

Given an Option<T> and a mapping function FnOnce(T) -> U, the method map returns an Option<U>:

fn () {
    // Option<i32> => Fn(i32) -> String => Option<String>
    // Some(i32)   =>    i32  -> String => Some(i32)
    let : <> = (5);
    let : <> = .(|| .());
    !(, (::("5")));

    // Option<i32> => Fn(i32) -> String => Option<String>
    // None                             => None
    let : <> = ;
    let : <> = .(|| .());
    !(, );
}

Example 2: Result

Result is generic over two types: a success type S and error type E. Therefore, any potential functor needs to map either S or E, while the other type can be restricted as needed for a practical implementation of fmap.

Mapping The Success Type S

Result with Result::map is a functor, mapping the success type S.

impl<, > <, > {
    pub fn <>(, : F) -> <, >
    where
        F: () -> ,
    {
        match  {
            () => (()),
            () => (),
        }
    }
}

Given a Result<T, E> and a mapping function FnOnce(T) -> U, the method map returns a Result<U, E>.

fn () {
    // Result<i32, &str> => Fn(i32) -> String => Result<String, &str>
    // Ok(i32)           =>    i32  -> String => Ok(i32)
    let : <, &> = (5);
    let : <, &> = .(|| .());
    !(, (::("5")));

    // Result<i32, &str> => Fn(i32) -> String => Result<String, &str>
    // Err(&str)                              => Err(&str)
    let : <, &> = ("invalid integer");
    let : <, &> = .(|| .());
    !(, ("invalid integer"));
}

Mapping The Error Type E

Result with Result::map_err is a functor, mapping the error type E.

impl<, > <, > {
    pub fn <>(, : F) -> <, >
    where
        F: () -> ,
    {
        match  {
            () => (),
            () => (()),
        }
    }
}

Given a Result<S, T> and a mapping function FnOnce(T) -> U, the method map_err returns a Result<S, U>.

fn () {
    // Result<i32, &str> => Fn(&str) -> bool => Result<i32, bool>
    // Ok(i32)                               => Ok(i32)
    let : <, &> = (5);
    let : <, > = .(|| .() > 5);
    !(, (5));

    // Result<i32, &str> => Fn(&str) -> bool => Result<i32, bool>
    // Err(&str)         =>    &str  -> bool => Err(bool)
    let : <, &> = ("invalid integer");
    let : <, > = .(|| .() > 5);
    !(, (true));
}

Example 3: [T N]

[T N] with <[T N]>::map is a functor.

impl<, const : > [; ] {
    pub fn <, >(, : ) -> [; ]
    where
        : () -> ,
    {
        .(NeverShortCircuit::wrap_mut_1(f)).0
    }
}

Given an array [T N] and a mapping function FnMut(T) -> U, the method map returns an array [U N].

fn () {
    // [i32; 5] => Fn(i32) -> bool => [bool; 5]
    let : [; 5] = [1, 2, 3, 4, 5];
    let : [; 5] = .(||  >= 3);
    !(, [false, false, true, true, true]);
}

Example 4: impl Iterator

Any implementation of Iterator with Iterator::map is a functor. The implementation is generic over the associated type Iterator::item.

trait  {
    type ;

    fn <, >(, : ) -> Map<, >
    where
        ::Sized,
        : (::) -> ,
    {
        Map::new(, f)
    }
}

Notably, Map<Self, F> implements the following:

impl<, , >  for Map<, >
where
    : ,
    : (< as >::) -> ,
    type  = U;

Given an impl Iterator<Item = T> and a mapping function FnMut(T) -> U, the method map returns an impl Iterator<Item = U>.

fn () {
    // impl Iterator<Item = u32> => Fn(u32) -> bool
    //                           => impl Iterator<Item = bool>
    let : &mut dyn < = > = &mut [1, 2, 3, 4].();
    let : &mut dyn < = > = &mut .(||  < 10);

    for  in  {
        !();
    }
}

Monad

In Rust, the monad pattern resembles a generic Monad<T> with a practical implementation of the following function:

fn <, , >(: Monad<>, : ) -> Monad<>
where
    : () -> Monad<>,
{
    !()
}

In English:

If I have a Monad of T, and I have a function that turns Ts into "Monad of U"s, the function bind gives me a Monad of U.

Example 1: Option

Option with Option::and_then is a monad.

impl<> <> {
  pub fn <, >(, : ) -> <>
    where
        : () -> <>,
    {
        match  {
            () => (),
             => ,
        }
    }
}

Given an Option<T> and a mapping function FnOnce(T) -> Option<U>, the method map returns an Option<U>.

// Taken from the standard library example:
// Fn(u32) -> Option<String>
fn (: ) -> <> {
    .().(|| .())
}

fn () {
    // Option<u32> => Fn(u32) -> Option<String> => Option<String>
    // Some(u32)   =>    u32  -> Some(String)   => Some(String)
    let : <> = (2);
    let : <> = .();
    !(, (::("4")));

    // Option<u32> => Fn(u32) -> Option<String> => Option<String>
    // Some(u32)   =>    u32  -> None           => None
    let : <> = (1_000_000);
    let : <> = .();
    !(, );

    // Option<u32> => Fn(u32) -> Option<String> => Option<String>
    // None                                     => None
    let : <> = ;
    let : <> = .();
    !(, );
}

Example 2: Result

Result is generic over two types: a success type S and error type E. Therefore, any potential monad needs to map either S or E, while the other type can be restricted as needed for a practical implementation of bind.

In the case of Result, there isn't many practical use for mapping the error type to another Result<T, E>

Mapping The Success Type S

Result with Result::and_then is a monad, mapping the success type S.

impl<, > <, > {
    pub fn <>(, : F) -> <, >
    where
        F: () -> <, >,
    {
        match  {
            () => (),
            () => (),
        }
    }
}

Given a Result<T, E> and a mapping function FnOnce(T) -> Result<U>, the method and_then returns a Result<U, E>.

// Taken from the standard library example:
// Fn(u32) -> Result<String, &str>
fn (: ) -> <, & > {
    .().(|| .()).("overflowed")
}

fn () {
    // Result<u32, &str> => Fn(u32) -> Result<String, &str> => Result<String, &str>
    // Ok(u32)           =>    u32  -> Some(String)         => Ok(String)
    let : <, &> = (2);
    let : <, &> = .();
    !(, (::("4")));

    // Result<u32, &str> => Fn(u32) -> Result<String, &str> => Result<String, &str>
    // Ok(u32)           =>    u32  -> Err(&str)            => Err(&str)
    let : <, &> = (1_000_000);
    let : <, &> = .();
    !(, ("overflowed"));

    // Result<u32, &str> => Fn(u32) -> Result<String, &str> => Result<String, &str>
    // Err(&str)                                            => Err(&str)
    let : <, &> = ("not a number");
    let : <, &> = .();
    !(, ("not a number"));
}

Mapping The Error Type E

This case does not provide many practical uses for it to warrant inclusion in the standard library.

Given a Result<S, T> and a mapping function FnOnce(T) -> Result<S, U>, the method returns a Result<S, U>.

This would mean the mapping function on the error type can possibly produce an Ok(S) with a value of the success type, essentially producing the value out of thin air or from the error itself.

Example 3: impl Iterator

Any implementation of Iterator with Iterator::flat_map is a monad. The implementation is generic over the associated type Iterator::item.

trait  {
    type ;

    fn <, >(, : ) -> FlatMap<, , >
    where
        ::Sized,
        : ,
        : (::) -> ,
    {
        FlatMap::new(, f)
    }
}

Notably, FlatMap<Self, U, F> implements the following:

impl<, , >  for FlatMap<, , >
where
    : ,
    : ,
    : (< as >::) -> ,
    type  = <U as >::;

Given an impl Iterator<Item = T> and a mapping function FnMut(T) -> impl Iterator<Item = U>, the method flat_map returns an impl Iterator<Item = U>.

// Fn(u32) -> impl Iterator<Item = u32>
fn (: ) -> impl < = > {
    0..=
}

fn () {
    // impl Iterator<Item = u32> => Fn(u32) -> impl Iterator<Item = u32>
    //                           => impl Iterator<Item = u32>
    let : &mut dyn < = > = &mut [1, 2, 3].();
    let : &mut dyn < = > = &mut .();

    !(
        .().::<<>>(),
        ![0, 1, 0, 1, 2, 0, 1, 2, 3]
    );
}

Conclusion

At the end of the day, although the function signatures and implementations seem complicated the intended outcomes are simple:

  1. Functor

    Functor<T>    +    (T) -> U         =    Functor<U>
  2. Monad

    Monad<T>    +    (T) -> Monad<U>    =    Monad<U>
codeintel::block_9a406edac18f37cd
fn fmap<T, U, F>(from: Functor<T>, func: F) -> Functor<U>
where
    F: Fn(T) -> U,
codeintel::block_9a406edac18f37cd::fmap
T
codeintel::block_9a406edac18f37cd::fmap
U
codeintel::block_9a406edac18f37cd::fmap
F: Fn(T) -> U
from: {unknown}
func: F
core::ops::function
pub trait Fn<Args>
where
    Self: FnMut<Args>,
    Args: Tuple,

The version of the call operator that takes an immutable receiver.

Instances of Fn can be called repeatedly without mutating state.

This trait (Fn) is not to be confused with [function pointers] (fn).

Fn is implemented automatically by closures which only take immutable references to captured variables or don’t capture anything at all, as well as (safe) [function pointers] (with some caveats, see their documentation for more details). Additionally, for any type F that implements Fn, &F implements Fn, too.

Since both FnMut and FnOnce are supertraits of Fn, any instance of Fn can be used as a parameter where a FnMut or FnOnce is expected.

Use Fn as a bound when you want to accept a parameter of function-like type and need to call it repeatedly and without mutating state (e.g., when calling it concurrently). If you do not need such strict requirements, use FnMut or FnOnce as bounds.

See the chapter on closures in The Rust Programming Language for some more information on this topic.

Also of note is the special syntax for Fn traits (e.g. Fn(usize, bool) -> usize). Those interested in the technical details of this can refer to the relevant section in the Rustonomicon.

Examples

Calling a closure

let square = |x| x * x;
assert_eq!(square(5), 25);

Using a Fn parameter

fn call_with_one<F>(func: F) -> usize
    where F: Fn(usize) -> usize {
    func(1)
}

let double = |x| x * 2;
assert_eq!(call_with_one(double), 2);
core::macros
macro_rules! todo

Indicates unfinished code.

This can be useful if you are prototyping and just want a placeholder to let your code pass type analysis.

The difference between unimplemented and todo! is that while todo! conveys an intent of implementing the functionality later and the message is “not yet implemented”, unimplemented! makes no such claims. Its message is “not implemented”.

Also, some IDEs will mark todo!s.

Panics

This will always panic because todo! is just a shorthand for panic! with a fixed, specific message.

Like panic!, this macro has a second form for displaying custom values.

Examples

Here’s an example of some in-progress code. We have a trait Foo:

trait Foo {
    fn bar(&self) -> u8;
    fn baz(&self);
    fn qux(&self) -> Result<u64, ()>;
}

We want to implement Foo on one of our types, but we also want to work on just bar() first. In order for our code to compile, we need to implement baz() and qux(), so we can use todo!:

struct MyStruct;

impl Foo for MyStruct {
    fn bar(&self) -> u8 {
        1 + 1
    }

    fn baz(&self) {
        // Let's not worry about implementing baz() for now
        todo!();
    }

    fn qux(&self) -> Result<u64, ()> {
        // We can add a message to todo! to display our omission.
        // This will display:
        // "thread 'main' panicked at 'not yet implemented: MyStruct is not yet quxable'".
        todo!("MyStruct is not yet quxable");
    }
}

fn main() {
    let s = MyStruct;
    s.bar();

    // We aren't even using baz() or qux(), so this is fine.
}
codeintel::block_c642de10032c27e9::Option
T
core::option
pub enum Option<T> {
    None,
    Some( /* … */ ),
}

The Option type. See the module level documentation for more.

codeintel::block_c642de10032c27e9::Option
impl<T> Option<T>
pub fn map<U, F>(self, func: F) -> Option<U>
where
    F: FnOnce(T) -> U,
codeintel::block_c642de10032c27e9::Option::map
U
codeintel::block_c642de10032c27e9::Option::map
F: FnOnce(T) -> U
self: Option<T>
core::ops::function
pub trait FnOnce<Args>
where
    Args: Tuple,

The version of the call operator that takes a by-value receiver.

Instances of FnOnce can be called, but might not be callable multiple times. Because of this, if the only thing known about a type is that it implements FnOnce, it can only be called once.

FnOnce is implemented automatically by closures that might consume captured variables, as well as all types that implement FnMut, e.g., (safe) [function pointers] (since FnOnce is a supertrait of FnMut).

Since both Fn and FnMut are subtraits of FnOnce, any instance of Fn or FnMut can be used where a FnOnce is expected.

Use FnOnce as a bound when you want to accept a parameter of function-like type and only need to call it once. If you need to call the parameter repeatedly, use FnMut as a bound; if you also need it to not mutate state, use Fn.

See the chapter on closures in The Rust Programming Language for some more information on this topic.

Also of note is the special syntax for Fn traits (e.g. Fn(usize, bool) -> usize). Those interested in the technical details of this can refer to the relevant section in the Rustonomicon.

Examples

Using a FnOnce parameter

fn consume_with_relish<F>(func: F)
    where F: FnOnce() -> String
{
    // `func` consumes its captured variables, so it cannot be run more
    // than once.
    println!("Consumed: {}", func());

    println!("Delicious!");

    // Attempting to invoke `func()` again will throw a `use of moved
    // value` error for `func`.
}

let x = String::from("x");
let consume_and_return_x = move || x;
consume_with_relish(consume_and_return_x);

// `consume_and_return_x` can no longer be invoked at this point
core::option::Option
Some(T)

Some value of type T.

let x: T
core::option::Option
None

No value.

codeintel::block_729715ddbef340ac
fn main()
let opt_a: Option<i32>
i32

The 32-bit signed integer type.

let opt_b: Option<String>
alloc::string
pub struct String {
    vec: Vec<u8>,
}

A UTF-8–encoded, growable string.

String is the most common string type. It has ownership over the contents of the string, stored in a heap-allocated buffer (see Representation). It is closely related to its borrowed counterpart, the primitive [str].

Examples

You can create a String from a literal string with [String::from]:

let hello = String::from("Hello, world!");

You can append a char to a String with the [push] method, and append a [&str] with the [push_str] method:

let mut hello = String::from("Hello, ");

hello.push('w');
hello.push_str("orld!");

If you have a vector of UTF-8 bytes, you can create a String from it with the [from_utf8] method:

// some bytes, in a vector
let sparkle_heart = vec![240, 159, 146, 150];

// We know these bytes are valid, so we'll use `unwrap()`.
let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();

assert_eq!("💖", sparkle_heart);

UTF-8

Strings are always valid UTF-8. If you need a non-UTF-8 string, consider OsString. It is similar, but without the UTF-8 constraint. Because UTF-8 is a variable width encoding, Strings are typically smaller than an array of the same chars:

// `s` is ASCII which represents each `char` as one byte
let s = "hello";
assert_eq!(s.len(), 5);

// A `char` array with the same contents would be longer because
// every `char` is four bytes
let s = ['h', 'e', 'l', 'l', 'o'];
let size: usize = s.into_iter().map(|c| size_of_val(&c)).sum();
assert_eq!(size, 20);

// However, for non-ASCII strings, the difference will be smaller
// and sometimes they are the same
let s = "💖💖💖💖💖";
assert_eq!(s.len(), 20);

let s = ['💖', '💖', '💖', '💖', '💖'];
let size: usize = s.into_iter().map(|c| size_of_val(&c)).sum();
assert_eq!(size, 20);

This raises interesting questions as to how s[i] should work. What should i be here? Several options include byte indices and char indices but, because of UTF-8 encoding, only byte indices would provide constant time indexing. Getting the ith char, for example, is available using [chars]:

let s = "hello";
let third_character = s.chars().nth(2);
assert_eq!(third_character, Some('l'));

let s = "💖💖💖💖💖";
let third_character = s.chars().nth(2);
assert_eq!(third_character, Some('💖'));

Next, what should s[i] return? Because indexing returns a reference to underlying data it could be &u8, &[u8], or something similar. Since we’re only providing one index, &u8 makes the most sense but that might not be what the user expects and can be explicitly achieved with [as_bytes()]:

// The first byte is 104 - the byte value of `'h'`
let s = "hello";
assert_eq!(s.as_bytes()[0], 104);
// or
assert_eq!(s.as_bytes()[0], b'h');

// The first byte is 240 which isn't obviously useful
let s = "💖💖💖💖💖";
assert_eq!(s.as_bytes()[0], 240);

Due to these ambiguities/restrictions, indexing with a usize is simply forbidden:

let s = "hello";

// The following will not compile!
println!("The first letter of s is {}", s[0]);

It is more clear, however, how &s[i..j] should work (that is, indexing with a range). It should accept byte indices (to be constant-time) and return a &str which is UTF-8 encoded. This is also called “string slicing”. Note this will panic if the byte indices provided are not character boundaries - see [is_char_boundary] for more details. See the implementations for [SliceIndex<str>] for more details on string slicing. For a non-panicking version of string slicing, see [get].

The [bytes] and [chars] methods return iterators over the bytes and codepoints of the string, respectively. To iterate over codepoints along with byte indices, use [char_indices].

Deref

String implements [Deref]<Target = [str]>, and so inherits all of [str]’s methods. In addition, this means that you can pass a String to a function which takes a [&str] by using an ampersand (&):

fn takes_str(s: &str) { }

let s = String::from("Hello");

takes_str(&s);

This will create a [&str] from the String and pass it in. This conversion is very inexpensive, and so generally, functions will accept [&str]s as arguments unless they need a String for some specific reason.

In certain cases Rust doesn’t have enough information to make this conversion, known as [Deref] coercion. In the following example a string slice &'a str implements the trait TraitExample, and the function example_func takes anything that implements the trait. In this case Rust would need to make two implicit conversions, which Rust doesn’t have the means to do. For that reason, the following example will not compile.

trait TraitExample {}

impl<'a> TraitExample for &'a str {}

fn example_func<A: TraitExample>(example_arg: A) {}

let example_string = String::from("example_string");
example_func(&example_string);

There are two options that would work instead. The first would be to change the line example_func(&example_string); to example_func(example_string.as_str());, using the method [as_str()] to explicitly extract the string slice containing the string. The second way changes example_func(&example_string); to example_func(&*example_string);. In this case we are dereferencing a String to a [str], then referencing the [str] back to [&str]. The second way is more idiomatic, however both work to do the conversion explicitly rather than relying on the implicit conversion.

Representation

A String is made up of three components: a pointer to some bytes, a length, and a capacity. The pointer points to the internal buffer which String uses to store its data. The length is the number of bytes currently stored in the buffer, and the capacity is the size of the buffer in bytes. As such, the length will always be less than or equal to the capacity.

This buffer is always stored on the heap.

You can look at these with the [as_ptr], [len], and [capacity] methods:

let story = String::from("Once upon a time...");

// Deconstruct the String into parts.
let (ptr, len, capacity) = story.into_raw_parts();

// story has nineteen bytes
assert_eq!(19, len);

// We can re-build a String out of ptr, len, and capacity. This is all
// unsafe because we are responsible for making sure the components are
// valid:
let s = unsafe { String::from_raw_parts(ptr, len, capacity) } ;

assert_eq!(String::from("Once upon a time..."), s);

If a String has enough capacity, adding elements to it will not re-allocate. For example, consider this program:

let mut s = String::new();

println!("{}", s.capacity());

for _ in 0..5 {
    s.push_str("hello");
    println!("{}", s.capacity());
}

This will output the following:

0
8
16
16
32
32

At first, we have no memory allocated at all, but as we append to the string, it increases its capacity appropriately. If we instead use the [with_capacity] method to allocate the correct capacity initially:

let mut s = String::with_capacity(25);

println!("{}", s.capacity());

for _ in 0..5 {
    s.push_str("hello");
    println!("{}", s.capacity());
}

We end up with a different output:

25
25
25
25
25
25

Here, there’s no need to allocate more memory inside the loop.

core::option::Option
impl<T> Option<T>
pub const fn map<U, F>(self, f: F) -> Option<U>
where
    F: FnOnce(T) -> U + Destruct,

Maps an Option<T> to Option<U> by applying a function to a contained value (if Some) or returns None (if None).

Examples

Calculates the length of an Option<String> as an Option<usize>, consuming the original:

let maybe_some_string = Some(String::from("Hello, World!"));
// `Option::map` takes self *by value*, consuming `maybe_some_string`
let maybe_some_len = maybe_some_string.map(|s| s.len());
assert_eq!(maybe_some_len, Some(13));

let x: Option<&str> = None;
assert_eq!(x.map(|s| s.len()), None);
i: i32
alloc::string
impl<T> ToString for T
fn to_string(&self) -> String
where
    // Bounds from impl:
    T: fmt::Display + ?Sized,

Converts the given value to a String.

Examples

let i = 5;
let five = String::from("5");

assert_eq!(five, i.to_string());
core::macros
macro_rules! assert_eq

Asserts that two expressions are equal to each other (using PartialEq).

Assertions are always checked in both debug and release builds, and cannot be disabled. See [debug_assert_eq!] for assertions that are disabled in release builds by default.

On panic, this macro will print the values of the expressions with their debug representations.

Like assert, this macro has a second form, where a custom panic message can be provided.

Examples

let a = 3;
let b = 1 + 2;
assert_eq!(a, b);

assert_eq!(a, b, "we are testing addition with {} and {}", a, b);
alloc::string::String
fn from(s: &str) -> String

Converts a &str into a String.

The result is allocated on the heap.

codeintel::block_f9a7dd82d09e3daa::Result
T
codeintel::block_f9a7dd82d09e3daa::Result
E
core::result
pub enum Result<T, E> {
    Ok( /* … */ ),
    Err( /* … */ ),
}

Result is a type that represents either success (Ok) or failure (Err).

See the module documentation for details.

codeintel::block_f9a7dd82d09e3daa::Result
impl<T, E> Result<T, E>
pub fn map<U>(self, func: F) -> Result<U, E>
where
    F: FnOnce(T) -> U,
codeintel::block_f9a7dd82d09e3daa::Result::map
U
self: Result<T, E>
func: {unknown}
core::result::Result
Ok(T)

Contains the success value

let t: T
core::result::Result
Err(E)

Contains the error value

let e: E
codeintel::block_9ec9daf66e12e19b
fn main()
let res_a: Result<i32, &str>
str

String slices.

See also the std::str module.

The str type, also called a ‘string slice’, is the most primitive string type. It is usually seen in its borrowed form, &str. It is also the type of string literals, &'static str.

Basic Usage

String literals are string slices:

let hello_world = "Hello, World!";

Here we have declared a string slice initialized with a string literal. String literals have a static lifetime, which means the string hello_world is guaranteed to be valid for the duration of the entire program. We can explicitly specify hello_world’s lifetime as well:

let hello_world: &'static str = "Hello, world!";

Representation

A &str is made up of two components: a pointer to some bytes, and a length. You can look at these with the [as_ptr] and [len] methods:

use std::slice;
use std::str;

let story = "Once upon a time...";

let ptr = story.as_ptr();
let len = story.len();

// story has nineteen bytes
assert_eq!(19, len);

// We can re-build a str out of ptr and len. This is all unsafe because
// we are responsible for making sure the two components are valid:
let s = unsafe {
    // First, we build a &[u8]...
    let slice = slice::from_raw_parts(ptr, len);

    // ... and then convert that slice into a string slice
    str::from_utf8(slice)
};

assert_eq!(s, Ok(story));

Note: This example shows the internals of &str. unsafe should not be used to get a string slice under normal circumstances. Use as_str instead.

Invariant

Rust libraries may assume that string slices are always valid UTF-8.

Constructing a non-UTF-8 string slice is not immediate undefined behavior, but any function called on a string slice may assume that it is valid UTF-8, which means that a non-UTF-8 string slice can lead to undefined behavior down the road.

let res_b: Result<String, &str>
core::result::Result
impl<T, E> Result<T, E>
pub const fn map<U, F>(self, op: F) -> Result<U, E>
where
    F: FnOnce(T) -> U + Destruct,

Maps a Result<T, E> to Result<U, E> by applying a function to a contained Ok value, leaving an Err value untouched.

This function can be used to compose the results of two functions.

Examples

Print the numbers on each line of a string multiplied by two.

let line = "1\n2\n3\n4\n";

for num in line.lines() {
    match num.parse::<i32>().map(|i| i * 2) {
        Ok(n) => println!("{n}"),
        Err(..) => {}
    }
}
codeintel::block_f133e041699206fb::Result
S
codeintel::block_f133e041699206fb::Result
T
codeintel::block_f133e041699206fb::Result
impl<S, T> Result<S, T>
pub fn map_err<U>(self, func: F) -> Result<S, U>
where
    F: FnOnce(T) -> U,
codeintel::block_f133e041699206fb::Result::map_err
U
self: Result<S, T>
let t: S
let e: T
codeintel::block_edf2f57e06444889
fn main()
let res_b: Result<i32, bool>
bool

The boolean type.

The bool represents a value, which could only be either true or false. If you cast a bool into an integer, true will be 1 and false will be 0.

Basic usage

bool implements various traits, such as [BitAnd], [BitOr], [Not], etc., which allow us to perform boolean operations using &, | and !.

if requires a bool value as its conditional. assert!, which is an important macro in testing, checks whether an expression is true and panics if it isn’t.

let bool_val = true & false | false;
assert!(!bool_val);

Examples

A trivial example of the usage of bool:

let praise_the_borrow_checker = true;

// using the `if` conditional
if praise_the_borrow_checker {
    println!("oh, yeah!");
} else {
    println!("what?!!");
}

// ... or, a match pattern
match praise_the_borrow_checker {
    true => println!("keep praising!"),
    false => println!("you should praise!"),
}

Also, since bool implements the Copy trait, we don’t have to worry about the move semantics (just like the integer and float primitives).

Now an example of bool cast to integer type:

assert_eq!(true as i32, 1);
assert_eq!(false as i32, 0);
core::result::Result
impl<T, E> Result<T, E>
pub const fn map_err<F, O>(self, op: O) -> Result<T, F>
where
    O: FnOnce(E) -> F + Destruct,

Maps a Result<T, E> to Result<T, F> by applying a function to a contained Err value, leaving an Ok value untouched.

This function can be used to pass through a successful result while handling an error.

Examples

fn stringify(x: u32) -> String { format!("error code: {x}") }

let x: Result<u32, u32> = Ok(2);
assert_eq!(x.map_err(stringify), Ok(2));

let x: Result<u32, u32> = Err(13);
assert_eq!(x.map_err(stringify), Err("error code: 13".to_string()));
s: &str
core::str
pub const fn len(&self) -> usize

Returns the length of self.

This length is in bytes, not [char]s or graphemes. In other words, it might not be what a human considers the length of the string.

Examples

let len = "foo".len();
assert_eq!(3, len);

assert_eq!("ƒoo".len(), 4); // fancy f!
assert_eq!("ƒoo".chars().count(), 3);
codeintel::block_e40023f93115775c
T
codeintel::block_e40023f93115775c
const N: usize
usize

The pointer-sized unsigned integer type.

The size of this primitive is how many bytes it takes to reference any location in memory. For example, on a 32 bit target, this is 4 bytes and on a 64 bit target, this is 8 bytes.

codeintel::block_e40023f93115775c
impl<T, const N: usize> [T; N]
pub fn map<F, U>(self, func: F) -> [U; {const}]
where
    F: FnMut(T) -> U,
codeintel::block_e40023f93115775c::map
F: FnMut(T) -> U
codeintel::block_e40023f93115775c::map
U
self: [T; N]
core::ops::function
pub trait FnMut<Args>
where
    Self: FnOnce<Args>,
    Args: Tuple,

The version of the call operator that takes a mutable receiver.

Instances of FnMut can be called repeatedly and may mutate state.

FnMut is implemented automatically by closures which take mutable references to captured variables, as well as all types that implement Fn, e.g., (safe) [function pointers] (since FnMut is a supertrait of Fn). Additionally, for any type F that implements FnMut, &mut F implements FnMut, too.

Since FnOnce is a supertrait of FnMut, any instance of FnMut can be used where a FnOnce is expected, and since Fn is a subtrait of FnMut, any instance of Fn can be used where FnMut is expected.

Use FnMut as a bound when you want to accept a parameter of function-like type and need to call it repeatedly, while allowing it to mutate state. If you don’t want the parameter to mutate state, use Fn as a bound; if you don’t need to call it repeatedly, use FnOnce.

See the chapter on closures in The Rust Programming Language for some more information on this topic.

Also of note is the special syntax for Fn traits (e.g. Fn(usize, bool) -> usize). Those interested in the technical details of this can refer to the relevant section in the Rustonomicon.

Examples

Calling a mutably capturing closure

let mut x = 5;
{
    let mut square_x = || x *= x;
    square_x();
}
assert_eq!(x, 25);

Using a FnMut parameter

fn do_twice<F>(mut func: F)
    where F: FnMut()
{
    func();
    func();
}

let mut x: usize = 1;
{
    let add_two_to_x = || x += 2;
    do_twice(add_two_to_x);
}

assert_eq!(x, 5);
core::array
impl<T, const N: usize> [T; N]
pub fn try_map<R>(self, f: impl FnMut(T) -> R) -> ChangeOutputType<R, [R::Output; {const}]>
where
    R: Try<Residual: Residual<[R::Output; {const}]>>,

A fallible function f applied to each element on array self in order to return an array the same size as self or the first error encountered.

The return type of this function depends on the return type of the closure. If you return Result<T, E> from the closure, you’ll get a Result<[T; N], E>. If you return Option<T> from the closure, you’ll get an Option<[T; N]>.

Examples

#![feature(array_try_map)]

let a = ["1", "2", "3"];
let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
assert_eq!(b, [2, 3, 4]);

let a = ["1", "2a", "3"];
let b = a.try_map(|v| v.parse::<u32>());
assert!(b.is_err());

use std::num::NonZero;

let z = [1, 2, 0, 3, 4];
assert_eq!(z.try_map(NonZero::new), None);

let a = [1, 2, 3];
let b = a.try_map(NonZero::new);
let c = b.map(|x| x.map(NonZero::get));
assert_eq!(c, Some(a));
codeintel::block_c4d7c785ce85b5e3
fn main()
let arr_a: [i32; 5]
let arr_b: [bool; 5]
core::array
impl<T, const N: usize> [T; N]
pub fn map<F, U>(self, f: F) -> [U; {const}]
where
    F: FnMut(T) -> U,

Returns an array of the same size as self, with function f applied to each element in order.

If you don’t necessarily need a new fixed-size array, consider using Iterator::map instead.

Note on performance and stack usage

Unfortunately, usages of this method are currently not always optimized as well as they could be. This mainly concerns large arrays, as mapping over small arrays seem to be optimized just fine. Also note that in debug mode (i.e. without any optimizations), this method can use a lot of stack space (a few times the size of the array or more).

Therefore, in performance-critical code, try to avoid using this method on large arrays or check the emitted code. Also try to avoid chained maps (e.g. arr.map(...).map(...)).

In many cases, you can instead use Iterator::map by calling .iter() or .into_iter() on your array. [T; N]::map is only necessary if you really need a new array of the same size as the result. Rust’s lazy iterators tend to get optimized very well.

Examples

let x = [1, 2, 3];
let y = x.map(|v| v + 1);
assert_eq!(y, [2, 3, 4]);

let x = [1, 2, 3];
let mut temp = 0;
let y = x.map(|v| { temp += 1; v * temp });
assert_eq!(y, [1, 4, 9]);

let x = ["Ferris", "Bueller's", "Day", "Off"];
let y = x.map(|v| v.len());
assert_eq!(y, [6, 9, 3, 3]);
codeintel::block_5bbf26dfed5c306a
trait Iterator
codeintel::block_5bbf26dfed5c306a::Iterator
type Item
codeintel::block_5bbf26dfed5c306a::Iterator
trait Iterator
fn map<U, F>(self, func: F) -> Map<Self, F>
where
    F: FnMut(Self::Item) -> U,
codeintel::block_5bbf26dfed5c306a::Iterator::map
U
codeintel::block_5bbf26dfed5c306a::Iterator::map
F: FnMut(<Self as Iterator>::Item) -> U
self: Self
codeintel::block_5bbf26dfed5c306a::Iterator
Self: ?Sized
codeintel::block_27bf027271a3aeec
U
codeintel::block_27bf027271a3aeec
I: Iterator
codeintel::block_27bf027271a3aeec
F: FnMut(<I as Iterator>::Item) -> U
core::iter::traits::iterator
pub trait Iterator

A trait for dealing with iterators.

This is the main iterator trait. For more about the concept of iterators generally, please see the [module-level documentation]. In particular, you may want to know how to implement Iterator.

core::iter::traits::iterator::Iterator
pub type Item

The type of the elements being iterated over.

codeintel::block_27bf027271a3aeec
type Item = U
codeintel::block_365a599de02caeb9
fn main()
let iter_a: &mut (dyn Iterator<Item = u32> + 'static)
u32

The 32-bit unsigned integer type.

core::array::iter
impl<T, const N: usize> IntoIterator for [T; N]
fn into_iter(self) -> Self::IntoIter

Creates a consuming iterator, that is, one that moves each value out of the array (from start to end).

The array cannot be used after calling this unless T implements Copy, so the whole array is copied.

Arrays have special behavior when calling .into_iter() prior to the 2021 edition – see the [array] Editions section for more information.

let iter_b: &mut (dyn Iterator<Item = bool> + 'static)
core::iter::traits::iterator::Iterator
pub trait Iterator
pub fn map<B, F>(self, f: F) -> Map<Self, F>
where
    Self: Sized,
    F: FnMut(Self::Item) -> B,

Takes a closure and creates an iterator which calls that closure on each element.

map() transforms one iterator into another, by means of its argument: something that implements FnMut. It produces a new iterator which calls this closure on each element of the original iterator.

If you are good at thinking in types, you can think of map() like this: If you have an iterator that gives you elements of some type A, and you want an iterator of some other type B, you can use map(), passing a closure that takes an A and returns a B.

map() is conceptually similar to a for loop. However, as map() is lazy, it is best used when you’re already working with other iterators. If you’re doing some sort of looping for a side effect, it’s considered more idiomatic to use for than map().

Examples

Basic usage:

let a = [1, 2, 3];

let mut iter = a.iter().map(|x| 2 * x);

assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), Some(6));
assert_eq!(iter.next(), None);

If you’re doing some sort of side effect, prefer for to map():

// don't do this:
(0..5).map(|x| println!("{x}"));

// it won't even execute, as it is lazy. Rust will warn you about this.

// Instead, use a for-loop:
for x in 0..5 {
    println!("{x}");
}
i: u32
let b: bool
core::macros::builtin
macro_rules! assert

Asserts that a boolean expression is true at runtime.

This will invoke the panic macro if the provided expression cannot be evaluated to true at runtime.

Uses

Assertions are always checked in both debug and release builds, and cannot be disabled. See debug_assert for assertions that are not enabled in release builds by default.

Unsafe code may rely on assert! to enforce run-time invariants that, if violated could lead to unsafety.

Other use-cases of assert! include testing and enforcing run-time invariants in safe code (whose violation cannot result in unsafety).

Custom Messages

This macro has a second form, where a custom panic message can be provided with or without arguments for formatting. See std::fmt for syntax for this form. Expressions used as format arguments will only be evaluated if the assertion fails.

Examples

// the panic message for these assertions is the stringified value of the
// expression given.
assert!(true);

fn some_computation() -> bool {
    // Some expensive computation here
    true
}

assert!(some_computation());

// assert with a custom message
let x = true;
assert!(x, "x wasn't true!");

let a = 3; let b = 27;
assert!(a + b == 30, "a = {}, b = {}", a, b);
codeintel::block_ed3c40f61c15f5fd
fn bind<T, U, F>(from: Monad<T>, func: F) -> Monad<U>
where
    F: Fn(T) -> Monad<U>,
codeintel::block_ed3c40f61c15f5fd::bind
T
codeintel::block_ed3c40f61c15f5fd::bind
U
codeintel::block_ed3c40f61c15f5fd::bind
F: Fn(T) -> {unknown}
codeintel::block_6a070137e7b254c5::Option
T
codeintel::block_6a070137e7b254c5::Option
impl<T> Option<T>
pub fn and_then<U, F>(self, func: F) -> Option<U>
where
    F: FnOnce(T) -> Option<U>,
codeintel::block_6a070137e7b254c5::Option::and_then
U
codeintel::block_6a070137e7b254c5::Option::and_then
F: FnOnce(T) -> Option<U>
codeintel::block_fc49fa3e778ad17d
fn sq_then_to_string(x: u32) -> Option<String>
x: u32
core::num
pub const fn checked_mul(self, rhs: Self) -> Option<Self>

Checked integer multiplication. Computes self * rhs, returning None if overflow occurred.

Examples

sq: u32
codeintel::block_fc49fa3e778ad17d
fn main()
let opt_a: Option<u32>
core::option::Option
impl<T> Option<T>
pub const fn and_then<U, F>(self, f: F) -> Option<U>
where
    F: FnOnce(T) -> Option<U> + Destruct,

Returns None if the option is None, otherwise calls f with the wrapped value and returns the result.

Some languages call this operation flatmap.

Examples

fn sq_then_to_string(x: u32) -> Option<String> {
    x.checked_mul(x).map(|sq| sq.to_string())
}

assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
assert_eq!(None.and_then(sq_then_to_string), None);

Often used to chain fallible operations that may return None.

let arr_2d = [["A0", "A1"], ["B0", "B1"]];

let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
assert_eq!(item_0_1, Some(&"A1"));

let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
assert_eq!(item_2_0, None);
codeintel::block_376034b8ef58d566::Result
T
codeintel::block_376034b8ef58d566::Result
E
codeintel::block_376034b8ef58d566::Result
impl<T, E> Result<T, E>
pub fn map<U>(self, func: F) -> Result<U, E>
where
    F: FnOnce(T) -> Result<U, E>,
codeintel::block_376034b8ef58d566::Result::map
U
codeintel::block_a4e625e6d975e98b
fn sq_then_to_string(x: u32) -> Result<String, &'static str>
'static
core::option::Option
impl<T> Option<T>
pub const fn ok_or<E>(self, err: E) -> Result<T, E>
where
    E: Destruct,

Transforms the Option<T> into a Result<T, E>, mapping [Some(v)] to [Ok(v)] and None to [Err(err)].

Arguments passed to ok_or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use [ok_or_else], which is lazily evaluated.

Examples

let x = Some("foo");
assert_eq!(x.ok_or(0), Ok("foo"));

let x: Option<&str> = None;
assert_eq!(x.ok_or(0), Err(0));
codeintel::block_a4e625e6d975e98b
fn main()
let res_a: Result<u32, &str>
core::result::Result
impl<T, E> Result<T, E>
pub const fn and_then<U, F>(self, op: F) -> Result<U, E>
where
    F: FnOnce(T) -> Result<U, E> + Destruct,

Calls op if the result is Ok, otherwise returns the Err value of self.

This function can be used for control flow based on Result values.

Examples

fn sq_then_to_string(x: u32) -> Result<String, &'static str> {
    x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")
}

assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));
assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));
assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));

Often used to chain fallible operations that may return Err.

use std::{io::ErrorKind, path::Path};

// Note: on Windows "/" maps to "C:\"
let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());
assert!(root_modified_time.is_ok());

let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());
assert!(should_fail.is_err());
assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
codeintel::block_403d209d8bc88bd1
trait Iterator
codeintel::block_403d209d8bc88bd1::Iterator
type Item
codeintel::block_403d209d8bc88bd1::Iterator
trait Iterator
fn flat_map<U, F>(self, func: F) -> FlatMap<Self, U, F>
where
    U: IntoIterator,
    F: FnMut(Self::Item) -> U,
codeintel::block_403d209d8bc88bd1::Iterator::flat_map
U: IntoIterator
codeintel::block_403d209d8bc88bd1::Iterator::flat_map
F: FnMut(<Self as Iterator>::Item) -> U
codeintel::block_403d209d8bc88bd1::Iterator
Self: ?Sized
core::iter::traits::collect
pub trait IntoIterator

Conversion into an Iterator.

By implementing IntoIterator for a type, you define how it will be converted to an iterator. This is common for types which describe a collection of some kind.

One benefit of implementing IntoIterator is that your type will work with Rust’s for loop syntax.

See also: FromIterator.

Examples

Basic usage:

let v = [1, 2, 3];
let mut iter = v.into_iter();

assert_eq!(Some(1), iter.next());
assert_eq!(Some(2), iter.next());
assert_eq!(Some(3), iter.next());
assert_eq!(None, iter.next());

Implementing IntoIterator for your type:

// A sample collection, that's just a wrapper over Vec<T>
#[derive(Debug)]
struct MyCollection(Vec<i32>);

// Let's give it some methods so we can create one and add things
// to it.
impl MyCollection {
    fn new() -> MyCollection {
        MyCollection(Vec::new())
    }

    fn add(&mut self, elem: i32) {
        self.0.push(elem);
    }
}

// and we'll implement IntoIterator
impl IntoIterator for MyCollection {
    type Item = i32;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

// Now we can make a new collection...
let mut c = MyCollection::new();

// ... add some stuff to it ...
c.add(0);
c.add(1);
c.add(2);

// ... and then turn it into an Iterator:
for (i, n) in c.into_iter().enumerate() {
    assert_eq!(i as i32, n);
}

It is common to use IntoIterator as a trait bound. This allows the input collection type to change, so long as it is still an iterator. Additional bounds can be specified by restricting on Item:

fn collect_as_strings<T>(collection: T) -> Vec<String>
where
    T: IntoIterator,
    T::Item: std::fmt::Debug,
{
    collection
        .into_iter()
        .map(|item| format!("{item:?}"))
        .collect()
}
codeintel::block_bc0c72a5bc6b4338
I: Iterator
codeintel::block_bc0c72a5bc6b4338
U: IntoIterator
codeintel::block_bc0c72a5bc6b4338
F: FnMut(<I as Iterator>::Item) -> U
codeintel::block_bc0c72a5bc6b4338
type Item = <U as IntoIterator>::Item
core::iter::traits::collect::IntoIterator
pub type Item

The type of the elements being iterated over.

codeintel::block_ba84de2b9130079d
fn range_to(i: u32) -> impl Iterator<Item = u32>
codeintel::block_ba84de2b9130079d
fn main()
let iter_b: &mut (dyn Iterator<Item = u32> + 'static)
core::iter::traits::iterator::Iterator
pub trait Iterator
pub fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where
    Self: Sized,
    U: IntoIterator,
    F: FnMut(Self::Item) -> U,

Creates an iterator that works like map, but flattens nested structure.

The [map] adapter is very useful, but only when the closure argument produces values. If it produces an iterator instead, there’s an extra layer of indirection. flat_map() will remove this extra layer on its own.

You can think of flat_map(f) as the semantic equivalent of [map]ping, and then [flatten]ing as in map(f).flatten().

Another way of thinking about flat_map(): [map]’s closure returns one item for each element, and flat_map()’s closure returns an iterator for each element.

Examples

let words = ["alpha", "beta", "gamma"];

// chars() returns an iterator
let merged: String = words.iter()
                          .flat_map(|s| s.chars())
                          .collect();
assert_eq!(merged, "alphabetagamma");
core::iter::traits::collect
impl<I> IntoIterator for I
fn into_iter(self) -> I
where
    // Bounds from impl:
    I: Iterator,

Creates an iterator from a value.

See the [module-level documentation] for more.

Examples

let v = [1, 2, 3];
let mut iter = v.into_iter();

assert_eq!(Some(1), iter.next());
assert_eq!(Some(2), iter.next());
assert_eq!(Some(3), iter.next());
assert_eq!(None, iter.next());
core::iter::traits::iterator::Iterator
pub trait Iterator
pub fn collect<B>(self) -> B
where
    B: FromIterator<Self::Item>,
    Self: Sized,

Transforms an iterator into a collection.

collect() can take anything iterable, and turn it into a relevant collection. This is one of the more powerful methods in the standard library, used in a variety of contexts.

The most basic pattern in which collect() is used is to turn one collection into another. You take a collection, call [iter] on it, do a bunch of transformations, and then collect() at the end.

collect() can also create instances of types that are not typical collections. For example, a String can be built from [char]s, and an iterator of Result<T, E> items can be collected into Result<Collection<T>, E>. See the examples below for more.

Because collect() is so general, it can cause problems with type inference. As such, collect() is one of the few times you’ll see the syntax affectionately known as the ‘turbofish’: ::<>. This helps the inference algorithm understand specifically which collection you’re trying to collect into.

Examples

Basic usage:

let a = [1, 2, 3];

let doubled: Vec<i32> = a.iter()
                         .map(|x| x * 2)
                         .collect();

assert_eq!(vec![2, 4, 6], doubled);

Note that we needed the : Vec<i32> on the left-hand side. This is because we could collect into, for example, a VecDeque<T> instead:

use std::collections::VecDeque;

let a = [1, 2, 3];

let doubled: VecDeque<i32> = a.iter().map(|x| x * 2).collect();

assert_eq!(2, doubled[0]);
assert_eq!(4, doubled[1]);
assert_eq!(6, doubled[2]);

Using the ‘turbofish’ instead of annotating doubled:

let a = [1, 2, 3];

let doubled = a.iter().map(|x| x * 2).collect::<Vec<i32>>();

assert_eq!(vec![2, 4, 6], doubled);

Because collect() only cares about what you’re collecting into, you can still use a partial type hint, _, with the turbofish:

let a = [1, 2, 3];

let doubled = a.iter().map(|x| x * 2).collect::<Vec<_>>();

assert_eq!(vec![2, 4, 6], doubled);

Using collect() to make a String:

let chars = ['g', 'd', 'k', 'k', 'n'];

let hello: String = chars.into_iter()
    .map(|x| x as u8)
    .map(|x| (x + 1) as char)
    .collect();

assert_eq!("hello", hello);

If you have a list of Result<T, E>s, you can use collect() to see if any of them failed:

let results = [Ok(1), Err("nope"), Ok(3), Err("bad")];

let result: Result<Vec<_>, &str> = results.into_iter().collect();

// gives us the first error
assert_eq!(Err("nope"), result);

let results = [Ok(1), Ok(3)];

let result: Result<Vec<_>, &str> = results.into_iter().collect();

// gives us the list of answers
assert_eq!(Ok(vec![1, 3]), result);
alloc::vec
pub struct Vec<T, A = Global>
where
    A: Allocator,
{
    buf: RawVec<T, A>,
    len: usize,
}

A contiguous growable array type, written as Vec<T>, short for ‘vector’.

Examples

let mut vec = Vec::new();
vec.push(1);
vec.push(2);

assert_eq!(vec.len(), 2);
assert_eq!(vec[0], 1);

assert_eq!(vec.pop(), Some(2));
assert_eq!(vec.len(), 1);

vec[0] = 7;
assert_eq!(vec[0], 7);

vec.extend([1, 2, 3]);

for x in &vec {
    println!("{x}");
}
assert_eq!(vec, [7, 1, 2, 3]);

The vec macro is provided for convenient initialization:

let mut vec1 = vec![1, 2, 3];
vec1.push(4);
let vec2 = Vec::from([1, 2, 3, 4]);
assert_eq!(vec1, vec2);

It can also initialize each element of a Vec<T> with a given value. This may be more efficient than performing allocation and initialization in separate steps, especially when initializing a vector of zeros:

let vec = vec![0; 5];
assert_eq!(vec, [0, 0, 0, 0, 0]);

// The following is equivalent, but potentially slower:
let mut vec = Vec::with_capacity(5);
vec.resize(5, 0);
assert_eq!(vec, [0, 0, 0, 0, 0]);

For more information, see Capacity and Reallocation.

Use a Vec<T> as an efficient stack:

let mut stack = Vec::new();

stack.push(1);
stack.push(2);
stack.push(3);

while let Some(top) = stack.pop() {
    // Prints 3, 2, 1
    println!("{top}");
}

Indexing

The Vec type allows access to values by index, because it implements the Index trait. An example will be more explicit:

let v = vec![0, 2, 4, 6];
println!("{}", v[1]); // it will display '2'

However be careful: if you try to access an index which isn’t in the Vec, your software will panic! You cannot do this:

let v = vec![0, 2, 4, 6];
println!("{}", v[6]); // it will panic!

Use [get] and [get_mut] if you want to check whether the index is in the Vec.

Slicing

A Vec can be mutable. On the other hand, slices are read-only objects. To get a slice, use &. Example:

fn read_slice(slice: &[usize]) {
    // ...
}

let v = vec![0, 1];
read_slice(&v);

// ... and that's all!
// you can also do it like this:
let u: &[usize] = &v;
// or like this:
let u: &[_] = &v;

In Rust, it’s more common to pass slices as arguments rather than vectors when you just want to provide read access. The same goes for [String] and [&str].

Capacity and reallocation

The capacity of a vector is the amount of space allocated for any future elements that will be added onto the vector. This is not to be confused with the length of a vector, which specifies the number of actual elements within the vector. If a vector’s length exceeds its capacity, its capacity will automatically be increased, but its elements will have to be reallocated.

For example, a vector with capacity 10 and length 0 would be an empty vector with space for 10 more elements. Pushing 10 or fewer elements onto the vector will not change its capacity or cause reallocation to occur. However, if the vector’s length is increased to 11, it will have to reallocate, which can be slow. For this reason, it is recommended to use Vec::with_capacity whenever possible to specify how big the vector is expected to get.

Guarantees

Due to its incredibly fundamental nature, Vec makes a lot of guarantees about its design. This ensures that it’s as low-overhead as possible in the general case, and can be correctly manipulated in primitive ways by unsafe code. Note that these guarantees refer to an unqualified Vec<T>. If additional type parameters are added (e.g., to support custom allocators), overriding their defaults may change the behavior.

Most fundamentally, Vec is and always will be a (pointer, capacity, length) triplet. No more, no less. The order of these fields is completely unspecified, and you should use the appropriate methods to modify these. The pointer will never be null, so this type is null-pointer-optimized.

However, the pointer might not actually point to allocated memory. In particular, if you construct a Vec with capacity 0 via Vec::new, vec![], Vec::with_capacity(0), or by calling [shrink_to_fit] on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized types inside a Vec, it will not allocate space for them. Note that in this case the Vec might not report a [capacity] of 0. Vec will allocate if and only if size_of::<T>() * capacity > 0. In general, Vec’s allocation details are very subtle — if you intend to allocate memory using a Vec and use it for something else (either to pass to unsafe code, or to build your own memory-backed collection), be sure to deallocate this memory by using from_raw_parts to recover the Vec and then dropping it.

If a Vec has allocated memory, then the memory it points to is on the heap (as defined by the allocator Rust is configured to use by default), and its pointer points to [len] initialized, contiguous elements in order (what you would see if you coerced it to a slice), followed by [capacity] - [len] logically uninitialized, contiguous elements.

A vector containing the elements 'a' and 'b' with capacity 4 can be visualized as below. The top part is the Vec struct, it contains a pointer to the head of the allocation in the heap, length and capacity. The bottom part is the allocation on the heap, a contiguous memory block.

            ptr      len  capacity
       +--------+--------+--------+
       | 0x0123 |      2 |      4 |
       +--------+--------+--------+
            |
            v
Heap   +--------+--------+--------+--------+
       |    'a' |    'b' | uninit | uninit |
       +--------+--------+--------+--------+
  • uninit represents memory that is not initialized, see [MaybeUninit].
  • Note: the ABI is not stable and Vec makes no guarantees about its memorylayout (including the order of fields).

Vec will never perform a “small optimization” where elements are actually stored on the stack for two reasons:

  • It would make it more difficult for unsafe code to correctly manipulate a Vec. The contents of a Vec wouldn’t have a stable address if it were only moved, and it would be more difficult to determine if a Vec had actually allocated memory.

  • It would penalize the general case, incurring an additional branch on every access.

Vec will never automatically shrink itself, even if completely empty. This ensures no unnecessary allocations or deallocations occur. Emptying a Vec and then filling it back up to the same [len] should incur no calls to the allocator. If you wish to free up unused memory, use [shrink_to_fit] or [shrink_to].

[push] and [insert] will never (re)allocate if the reported capacity is sufficient. [push] and [insert] will (re)allocate if [len] == [capacity]. That is, the reported capacity is completely accurate, and can be relied on. It can even be used to manually free the memory allocated by a Vec if desired. Bulk insertion methods may reallocate, even when not necessary.

Vec does not guarantee any particular growth strategy when reallocating when full, nor when [reserve] is called. The current strategy is basic and it may prove desirable to use a non-constant growth factor. Whatever strategy is used will of course guarantee O(1) amortized [push].

It is guaranteed, in order to respect the intentions of the programmer, that all of vec![e_1, e_2, ..., e_n], vec![x; n], and [Vec::with_capacity(n)] produce a Vec that requests an allocation of the exact size needed for precisely n elements from the allocator, and no other size (such as, for example: a size rounded up to the nearest power of 2). The allocator will return an allocation that is at least as large as requested, but it may be larger.

It is guaranteed that the [Vec::capacity] method returns a value that is at least the requested capacity and not more than the allocated capacity.

The method Vec::shrink_to_fit will attempt to discard excess capacity an allocator has given to a Vec. If [len] == [capacity], then a Vec<T> can be converted to and from a Box<[T]> without reallocating or moving the elements. Vec exploits this fact as much as reasonable when implementing common conversions such as [into_boxed_slice].

Vec will not specifically overwrite any data that is removed from it, but also won’t specifically preserve it. Its uninitialized memory is scratch space that it may use however it wants. It will generally just do whatever is most efficient or otherwise easy to implement. Do not rely on removed data to be erased for security purposes. Even if you drop a Vec, its buffer may simply be reused by another allocation. Even if you zero a Vec’s memory first, that might not actually happen because the optimizer does not consider this a side-effect that must be preserved. There is one case which we will not break, however: using unsafe code to write to the excess capacity, and then increasing the length to match, is always valid.

Currently, Vec does not guarantee the order in which elements are dropped. The order has changed in the past and may change again.

alloc::macros
macro_rules! vec

Creates a [Vec] containing the arguments.

vec! allows Vecs to be defined with the same syntax as array expressions. There are two forms of this macro:

  • Create a [Vec] containing a given list of elements:
let v = vec![1, 2, 3];
assert_eq!(v[0], 1);
assert_eq!(v[1], 2);
assert_eq!(v[2], 3);
  • Create a [Vec] from a given element and size:
let v = vec![1; 3];
assert_eq!(v, [1, 1, 1]);

Note that unlike array expressions this syntax supports all elements which implement Clone and the number of elements doesn’t have to be a constant.

This will use clone to duplicate an expression, so one should be careful using this with types having a nonstandard Clone implementation. For example, vec![Rc::new(1); 5] will create a vector of five references to the same boxed integer value, not five references pointing to independently boxed integers.

Also, note that vec![expr; 0] is allowed, and produces an empty vector. This will still evaluate expr, however, and immediately drop the resulting value, so be mindful of side effects.