Options & Results #

Other languages have two classic ways of handling failures and missing values: sentinel values like null or -1, and exceptions that can be thrown at any time from any function without being written in the signature. Both have the same problem — the compiler can’t force the programmer to deal with it. NullPointerException in Java and nil pointer dereference in Go are proof that this approach is simply not enough. Rust chooses a different path: the absence of values ​​and the possibility of failure are part of the type system, not exceptions. Option<T> represents a value that may or may not exist. Result<T, E> represents an operation that may succeed or fail. Both must be handled explicitly — otherwise the code will not compile.

Why Option and Result, Not Null and Exception #

Before looking at how to use both, it’s important to understand why Rust designed them as regular types, rather than as language-specific mechanisms.

When a function returns Option<String>, its signature explicitly communicates: “this function may not return a value.” Callers cannot ignore this possibility — the compiler forces them to handle the None case. Different from languages ​​that return String but can return null silently.

When a function returns Result<Data, IoError>, its signature communicates two things at once: the success value type (Data) and the possible error type (IoError). There are no hidden errors that can arise from functions that don’t include them in the signature.

// Other languages: functions that can return null or throw an exception
// String searchUser(int id) ← can be null, can be throw, not clear from signature

// Rust: signatures accurately reflect behavior
fn cari_pengguna(id: u32) -> Option<String> { ... }         // probably doesn't exist
fn baca_file(path: &str) -> Result<String, io::Error> { ... } // may fail
flowchart TD
    A[Fungsi dipanggil] --> B{Operasi berhasil?}
    B -- Ya, ada nilai --> C["Option::Some(T)"]
    B -- Tidak ada nilai --> D[Option::None]
    B -- Ya, sukses --> E["Result::Ok(T)"]
    B -- Gagal dengan error --> F["Result::Err(E)"]

    C --> G[Compiler paksa tangani kedua kasus]
    D --> G
    E --> H[Compiler paksa tangani kedua kasus]
    F --> H

    style C fill:#e8f5e9
    style D fill:#ffebee
    style E fill:#e8f5e9
    style F fill:#ffebee

Option<T> — Possible Missing Value #

Option<T> is an enum with two variants: Some(T) when the value is present, and None when it is not present. Use Option when the absence of a value is a normal condition that is not an error — for example searching for an element in a collection, retrieving the first element of a slice, or an optional field in a struct.

fn main() {
    // Create Option
    let ada: Option<i32> = Some(42);
    let tidak_ada: Option<i32> = None;

    // Collection returns Option when the element may not exist
    let angka = vec![1, 2, 3, 4, 5];
    let pertama: Option<&i32> = angka.first();       // Some(&1)
    let dari_indeks: Option<&i32> = angka.get(10);   // None — index out of bounds
    let dicari: Option<&i32> = angka.iter().find(|&&x| x > 3);  // Some(&4)

    // HashMap returns Option when key does not exist
    use std::collections::HashMap;
    let mut skor: HashMap<&str, i32> = HashMap::new();
    skor.insert("Alice", 100);

    let skor_alice: Option<&i32> = skor.get("Alice");  // Some(&100)
    let skor_bob: Option<&i32> = skor.get("Bob");      // None
}

Pattern Matching in Options #

match is the most explicit and flexible way to handle Option. Use it when you need different logic for Some and None, or when you need bindings to values ​​in Some.

fn deskripsi_skor(skor: Option<i32>) -> String {
    match skor {
        Some(s) if s >= 90 => format!("Sangat baik: {}", s),
        Some(s) if s >= 70 => format!("Baik: {}", s),
        Some(s) => format!("Perlu ditingkatkan: {}", s),
        None => String::from("Belum ada skor"),
    }
}

fn main() {
    println!("{}", deskripsi_skor(Some(95)));  // "Excellent: 95"
    println!("{}", deskripsi_skor(Some(75)));  // "Fine: 75"
    println!("{}", deskripsi_skor(None));      // "No score yet"

    // if let — more concise when only needing to handle Some
    let nilai = Some(42);
    if let Some(v) = nilai {
        println!("Nilai: {}", v);
    }

    // while let — iterate until None
    let mut stack = vec![1, 2, 3];
    while let Some(top) = stack.pop() {
        println!("Popped: {}", top);
    }
}

Method in Option #

Option has many methods that allow transformation and handling without explicit match. This makes the code more concise and composable.

fn main() {
    let ada: Option<i32> = Some(10);
    let tidak_ada: Option<i32> = None;

    // unwrap — take value, panic if None
    // ANTI-PATTERN: unwrap in production code without being sure it is not None
    let nilai = ada.unwrap();  // 10, but panic if it's not there.unwrap()

    // unwrap_or — default value if None
    let a = ada.unwrap_or(0);          // 10
    let b = tidak_ada.unwrap_or(0);    // 0

    // unwrap_or_else — default of closure (lazy evaluation)
    let c = tidak_ada.unwrap_or_else(|| {
        println!("Menghitung default...");
        42
    });

    // unwrap_or_default — default of the Default trait
    let d: i32 = tidak_ada.unwrap_or_default();  // 0 (default i32)

    // map — transforms values in Some, None to remain None
    let doubled = ada.map(|v| v * 2);        // Some(20)
    let doubled_none = tidak_ada.map(|v| v * 2); // None

    // map_or — map with default value if None
    let e = ada.map_or(0, |v| v * 2);        // 20
    let f = tidak_ada.map_or(0, |v| v * 2);  // 0

    // and_then — chaining operations that each return an Option
    let hasil = ada
        .and_then(|v| if v > 5 { Some(v * 2) } else { None })
        .and_then(|v| if v < 100 { Some(v) } else { None });
    println!("{:?}", hasil);  // Some(20)

    // filter — returns None if the value does not satisfy the condition
    let genap = ada.filter(|v| v % 2 == 0);  // Some(10)
    let ganjil = ada.filter(|v| v % 2 != 0); // None

    // or and or_else — fallback to another Option if None
    let g = tidak_ada.or(Some(99));   // Some(99)
    let h = ada.or(Some(99));         // Some(10) — there is no change

    // is_some and is_none — checking without consuming
    println!("{}", ada.is_some());        // true
    println!("{}", tidak_ada.is_none());  // true

    // as_ref — borrow content without consuming Option
    let s: Option<String> = Some(String::from("halo"));
    let panjang = s.as_ref().map(|v| v.len());  // s are still valid after this
    println!("{:?}", s);  // Some("hello") — does not move
}
flowchart LR
    A[Option<T>] --> B["map(f)"]
    A --> C["and_then(f)"]
    A --> D["filter(pred)"]
    A --> E["or(opt)"]

    B --> B1[Option<U> — value transformation]
    C --> C1[Option<U> — chaining Option-returning fn]
    D --> D1[Option<T> — None if condition is not met]
    E --> E1[Option<T> — fallback if None]

    style A fill:#e3f2fd
    style B1 fill:#e8f5e9
    style C1 fill:#e8f5e9
    style D1 fill:#e8f5e9
    style E1 fill:#e8f5e9

Result<T, E> — Operation that could fail #

Result<T, E> is an enum with two variants: Ok(T) when the operation succeeds, and Err(E) when it fails with an error of type E. Use Result when failure is something that needs to be communicated and handled — I/O operations, parsing, network requests, input validation.

use std::num::ParseIntError;
use std::io;

// Functions that can fail return a Result
fn parse_angka_positif(s: &str) -> Result<u32, String> {
    let angka: i64 = s.trim().parse().map_err(|_| format!("'{}' bukan angka valid", s))?;
    if angka < 0 {
        return Err(format!("Angka harus positif, dapat: {}", angka));
    }
    Ok(angka as u32)
}

fn main() {
    // Create Result manually
    let sukses: Result<i32, String> = Ok(42);
    let gagal: Result<i32, String> = Err(String::from("sesuatu gagal"));

    // Standard library operation that returns Result
    let parsed: Result<i32, ParseIntError> = "42".parse();
    let file_content: Result<String, io::Error> = std::fs::read_to_string("file.txt");

    // Pattern matching
    match parse_angka_positif("123") {
        Ok(n) => println!("Berhasil: {}", n),
        Err(e) => println!("Gagal: {}", e),
    }

    match parse_angka_positif("abc") {
        Ok(n) => println!("Berhasil: {}", n),
        Err(e) => println!("Gagal: {}", e),  // "Failed: 'abc' is not a valid number"
    }
}

Method on Result #

Result has a method that is very similar to Option, plus a special method for handling errors.

fn main() {
    let ok: Result<i32, String> = Ok(10);
    let err: Result<i32, String> = Err(String::from("error"));

    // unwrap and expect — panic when Err
    // ANTI-PATTERN: unwrap without context in production code
    let nilai = ok.unwrap();  // 10

    // TRUE: expect returns an informative error message
    let nilai = ok.expect("Seharusnya tidak gagal di tahap ini");

    // unwrap_or, unwrap_or_else, unwrap_or_default
    let a = err.unwrap_or(0);
    let b = err.unwrap_or_else(|e| {
        eprintln!("Error ditangani: {}", e);
        -1
    });

    // map — transformation Ok, Err is still Err
    let doubled = ok.map(|v| v * 2);         // Ok(20)
    let doubled_err = err.map(|v| v * 2);    // Err("error")

    // map_err — transformation Err, Ok remains Ok
    let konversi = err.map_err(|e| format!("Wrapped: {}", e));
    // Err("Wrapped: error")

    // and_then — chaining of Result-returning operations
    let hasil = ok
        .and_then(|v| if v > 5 { Ok(v * 2) } else { Err(String::from("terlalu kecil")) })
        .and_then(|v| Ok(v + 1));
    println!("{:?}", hasil);  // Ok(21)

    // or and or_else — fallback Result if Err
    let fallback = err.or(Ok(99));   // Ok(99)
    let fallback2 = err.or_else(|e| {
        println!("Mencoba recovery dari: {}", e);
        Ok(0)
    });

    // is_ok and is_err
    println!("{}", ok.is_ok());    // true
    println!("{}", err.is_err());  // true

    // ok() — convert Result to Option (Err to None)
    let sebagai_option: Option<i32> = ok.ok();   // Some(10)
    let err_option: Option<i32> = err.ok();      // None

    // err() — takes Err value as Option
    let error_value: Option<String> = err.err(); // Some("error")
}

Operator ? — Elegant Error Propagation #

The ? operator is a feature that makes error handling in Rust feel ergonomic. When installed after the expression Result, it does two things: if it is Ok, it extracts the value within it. If it’s Err, it immediately returns Err from the running function. This eliminates the need for repeated match for each operation that could fail.

use std::io;
use std::fs;
use std::num::ParseIntError;

// ANTI-PATTERN: match repeats for every operation — verbose and disrupts the flow
fn baca_angka_dari_file_verbose(path: &str) -> Result<i32, String> {
    let konten = match fs::read_to_string(path) {
        Ok(s) => s,
        Err(e) => return Err(e.to_string()),
    };
    let angka = match konten.trim().parse::<i32>() {
        Ok(n) => n,
        Err(e) => return Err(e.to_string()),
    };
    Ok(angka * 2)
}

// CORRECT: operator ? keeps the main flow readable
fn baca_angka_dari_file(path: &str) -> Result<i32, String> {
    let konten = fs::read_to_string(path).map_err(|e| e.to_string())?;
    let angka = konten.trim().parse::<i32>().map_err(|e| e.to_string())?;
    Ok(angka * 2)
}

? also works on Option — if it’s None, the function immediately returns None:

fn nama_depan(nama_lengkap: &str) -> Option<&str> {
    let bagian: Vec<&str> = nama_lengkap.split_whitespace().collect();
    let pertama = bagian.first()?;  // None if the string is empty
    Some(pertama)
}

fn inisial(nama_lengkap: &str) -> Option<char> {
    let depan = nama_depan(nama_lengkap)?;  // propagation None
    depan.chars().next()                     // first character
}
The ? operator can only be used in functions that return Result or Option. Using it on a regular main() will cause a compile error. The solution: change the signature main to fn main() -> Result<(), Box<dyn Error>>, or handle the error explicitly in main.
use std::error::Error;
use std::fs;

// main who can use ?
fn main() -> Result<(), Box<dyn Error>> {
    let konten = fs::read_to_string("config.txt")?;
    let nilai: i32 = konten.trim().parse()?;
    println!("Nilai dari config: {}", nilai);
    Ok(())
}

Chaining — Composition Without Nested Match #

One of the strengths of Option and Result is its functional composability. Instead of nested match which makes the code feel like a pyramid, you can chain operations linearly.

use std::collections::HashMap;

fn cari_email_pengguna(db: &HashMap<u32, HashMap<&str, &str>>, id: u32) -> Option<String> {
    // ANTI-PATTERN: nested match — hard to read and maintain
    match db.get(&id) {
        Some(profil) => {
            match profil.get("email") {
                Some(email) => {
                    if email.contains('@') {
                        Some(email.to_uppercase())
                    } else {
                        None
                    }
                }
                None => None,
            }
        }
        None => None,
    }
}

// TRUE: linear, easy-to-read chaining
fn cari_email_pengguna(db: &HashMap<u32, HashMap<&str, &str>>, id: u32) -> Option<String> {
    db.get(&id)
        .and_then(|profil| profil.get("email"))
        .filter(|email| email.contains('@'))
        .map(|email| email.to_uppercase())
}

fn main() {
    let mut db = HashMap::new();
    let mut profil = HashMap::new();
    profil.insert("email", "[email protected]");
    profil.insert("nama", "Budi");
    db.insert(1u32, profil);

    println!("{:?}", cari_email_pengguna(&db, 1));    // Some("[email protected]")
    println!("{:?}", cari_email_pengguna(&db, 99));   // None — id does not exist
}

The same pattern applies to Result:

use std::num::ParseIntError;

fn hitung_dari_input(a: &str, b: &str) -> Result<i32, String> {
    // Chaining Result — if one fails, the entire chain fails
    let x: i32 = a.trim()
        .parse()
        .map_err(|_: ParseIntError| format!("'{}' bukan angka valid", a))?;

    let y: i32 = b.trim()
        .parse()
        .map_err(|_: ParseIntError| format!("'{}' bukan angka valid", b))?;

    if y == 0 {
        return Err(String::from("Pembagi tidak boleh nol"));
    }

    Ok(x / y)
}

fn main() {
    println!("{:?}", hitung_dari_input("10", "2"));    // Ok(5)
    println!("{:?}", hitung_dari_input("10", "0"));    // Err("Divisor cannot be zero")
    println!("{:?}", hitung_dari_input("abc", "2"));   // Err("'abc' is not a valid number")
}

Conversion Between Option and Result #

In real code, you often need to convert between Option and Result — for example when a library function returns Option but you’re working in a context that expects Result.

fn main() {
    // Option → Result with ok_or and ok_or_else
    let ada: Option<i32> = Some(42);
    let tidak_ada: Option<i32> = None;

    let r1: Result<i32, &str> = ada.ok_or("nilai tidak ada");      // Ok(42)
    let r2: Result<i32, &str> = tidak_ada.ok_or("nilai tidak ada"); // Err("no value")

    // ok_or_else — lazy, errors are generated only when necessary
    let r3: Result<i32, String> = tidak_ada.ok_or_else(|| {
        format!("Nilai tidak ditemukan pada waktu {}", chrono_waktu())
    });

    // Result → Option with ok() and err()
    let ok: Result<i32, &str> = Ok(42);
    let err: Result<i32, &str> = Err("gagal");

    let opt1: Option<i32> = ok.ok();    // Some(42)
    let opt2: Option<i32> = err.ok();   // None — error thrown

    // Real scenario: search in HashMap, then process the results
    use std::collections::HashMap;

    let konfigurasi: HashMap<&str, &str> = [
        ("port", "8080"),
        ("timeout", "30"),
    ].into_iter().collect();

    fn ambil_port(config: &HashMap<&str, &str>) -> Result<u16, String> {
        config
            .get("port")
            .ok_or_else(|| String::from("Konfigurasi 'port' tidak ditemukan"))?
            .parse::<u16>()
            .map_err(|e| format!("Port tidak valid: {}", e))
    }

    match ambil_port(&konfigurasi) {
        Ok(port) => println!("Server berjalan di port {}", port),
        Err(e) => eprintln!("Error konfigurasi: {}", e),
    }
}

fn chrono_waktu() -> String { String::from("sekarang") }
flowchart TD
    A[Option<T>] -- "ok_or(e)" --> B[Result<T, E>]
    A -- "ok_or_else(|| e)" --> B
    B -- "ok()" --> C[Option<T>]
    B -- "err()" --> D[Option<E>]
    C -- "ok_or(...)" --> B

    style A fill:#e8f5e9
    style B fill:#e3f2fd
    style C fill:#e8f5e9
    style D fill:#fff3e0

Custom Error Type #

For larger applications, you need to define your own error types that represent all possible failures in your application domain.

use std::fmt;
use std::num::ParseIntError;
use std::io;

// Custom error definition with enum
#[derive(Debug)]
enum AppError {
    Io(io::Error),
    Parse(ParseIntError),
    Validasi(String),
    TidakDitemukan { resource: String, id: u32 },
}

// Display implementation for user friendly messages
impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            AppError::Io(e) => write!(f, "Error I/O: {}", e),
            AppError::Parse(e) => write!(f, "Error parsing: {}", e),
            AppError::Validasi(msg) => write!(f, "Error validasi: {}", msg),
            AppError::TidakDitemukan { resource, id } => {
                write!(f, "{} dengan id {} tidak ditemukan", resource, id)
            }
        }
    }
}

// Implementation of From for automatic conversion with operator ?
impl From<io::Error> for AppError {
    fn from(e: io::Error) -> Self {
        AppError::Io(e)
    }
}

impl From<ParseIntError> for AppError {
    fn from(e: ParseIntError) -> Self {
        AppError::Parse(e)
    }
}

// With the From implementation, the ? can convert errors automatically
fn proses_konfigurasi(path: &str) -> Result<u32, AppError> {
    let konten = std::fs::read_to_string(path)?;  // io::Error → AppError::Io auto
    let nilai: u32 = konten.trim().parse()?;       // ParseIntError → AppError::Auto parse

    if nilai == 0 {
        return Err(AppError::Validasi(String::from("Nilai tidak boleh nol")));
    }

    Ok(nilai)
}

fn main() {
    match proses_konfigurasi("config.txt") {
        Ok(nilai) => println!("Konfigurasi berhasil: {}", nilai),
        Err(AppError::Io(e)) => eprintln!("Gagal baca file: {}", e),
        Err(AppError::Parse(e)) => eprintln!("Format tidak valid: {}", e),
        Err(AppError::Validasi(msg)) => eprintln!("Validasi gagal: {}", msg),
        Err(e) => eprintln!("Error lain: {}", e),
    }
}

Using thiserror for Less Boilerplate #

Crate thiserror simplifies creating custom error types with derive macros:

# Cargo.toml
[dependencies]
thiserror = "1"
use thiserror::Error;

#[derive(Debug, Error)]
enum AppError {
    #[error("Error I/O: {0}")]
    Io(#[from] std::io::Error),

    #[error("Error parsing: {0}")]
    Parse(#[from] std::num::ParseIntError),

    #[error("Error validasi: {0}")]
    Validasi(String),

    #[error("{resource} dengan id {id} tidak ditemukan")]
    TidakDitemukan { resource: String, id: u32 },
}

// The From implementation is generated automatically by #[from]
// Display generated from attribute #[error("...")]
// The process_configuration code above can be used directly without changes

Using anyhow for Rapid Prototyping #

Crate anyhow is useful when you don’t care about specific error types — for example in binaries (not libraries) or when prototyping:

[dependencies]
anyhow = "1"
use anyhow::{Context, Result, bail, ensure};

fn baca_dan_proses(path: &str) -> Result<i32> {
    // Context adds a context message to the existing error
    let konten = std::fs::read_to_string(path)
        .with_context(|| format!("Gagal membaca file '{}'", path))?;

    let nilai: i32 = konten.trim().parse()
        .context("Isi file bukan angka yang valid")?;

    // bail! — shorthand for return Err(anyhow!(...))
    if nilai < 0 {
        bail!("Nilai harus positif, dapat: {}", nilai);
    }

    // ensure! — assert which returns Err if the condition is false
    ensure!(nilai < 1000, "Nilai {} melebihi batas maksimum 1000", nilai);

    Ok(nilai * 2)
}

fn main() -> Result<()> {
    let hasil = baca_dan_proses("input.txt")?;
    println!("Hasil: {}", hasil);
    Ok(())
}
Use thiserror for libraries — an explicit error type that allows library users to perform pattern matching. Use anyhow for binary or application code — it’s more ergonomic and doesn’t require detailed error enum definitions.

Collecting Results from Iterators #

When processing collections and individual items can fail, Rust provides an idiomatic way to collect the results.

fn main() {
    let input = vec!["1", "2", "3", "4", "5"];
    let salah = vec!["1", "dua", "3", "empat", "5"];

    // collect() to Result<Vec<T>, E> — fails if one item is Err
    let semua_ok: Result<Vec<i32>, _> = input.iter()
        .map(|s| s.parse::<i32>())
        .collect();
    println!("{:?}", semua_ok);  // Ok([1, 2, 3, 4, 5])

    let ada_error: Result<Vec<i32>, _> = salah.iter()
        .map(|s| s.parse::<i32>())
        .collect();
    println!("{:?}", ada_error);  // Err(ParseIntError { ... })

    // Separate Ok and Err — processes that are valid, ignore those that are not
    let (berhasil, gagal): (Vec<_>, Vec<_>) = salah.iter()
        .map(|s| s.parse::<i32>())
        .partition(Result::is_ok);

    let nilai: Vec<i32> = berhasil.into_iter().map(|r| r.unwrap()).collect();
    let error: Vec<_> = gagal.into_iter().map(|r| r.unwrap_err()).collect();

    println!("Berhasil: {:?}", nilai);  // [1, 3, 5]
    println!("Gagal: {:?}", error);     // [ParseIntError, ParseIntError]

    // filter_map — silently ignore None/Err
    let hanya_valid: Vec<i32> = salah.iter()
        .filter_map(|s| s.parse::<i32>().ok())
        .collect();
    println!("Hanya valid: {:?}", hanya_valid);  // [1, 3, 5]
}

When to Use Option vs Result #

Choosing between Option and Result isn’t just a matter of preference — there are semantic differences to understand.

Gunakan Option jika:
  ✓ Ketiadaan nilai adalah kondisi normal, bukan error
  ✓ Operasi pencarian yang mungkin tidak menemukan hasil
  ✓ Field opsional dalam struct
  ✓ Iterator yang bisa habis
  ✓ Nilai yang belum diinisialisasi

Gunakan Result jika:
  ✗ Kegagalan terjadi karena kondisi eksternal (I/O, network, parsing)
  ✗ Caller perlu tahu MENGAPA gagal, bukan hanya bahwa gagal
  ✗ Kegagalan adalah pengecualian dari alur normal
  ✗ Error perlu dilaporkan atau di-log
  ✗ Operasi yang membutuhkan resource dan bisa ditolak sistem

Examples that are often confusing:

// Searching HashMap — use Option
// There is nothing "wrong" if the key is not there
fn cari_pengguna(db: &HashMap<u32, String>, id: u32) -> Option<&String> {
    db.get(&id)
}

// Read users from database — use Result
// Can fail due to database connection, query error, etc.
fn ambil_pengguna(id: u32) -> Result<Pengguna, DbError> {
    // database connections can fail, queries can fail
    db.query("SELECT * FROM users WHERE id = ?", [id])
}

// Parse optional values from configuration
// Option if the field is optional, Result if the format must be valid
fn port_konfigurasi(config: &HashMap<&str, &str>) -> Result<Option<u16>, String> {
    match config.get("port") {
        None => Ok(None),  // no port = use default
        Some(s) => s.parse::<u16>()
            .map(Some)
            .map_err(|_| format!("Port '{}' tidak valid", s)),
    }
}

Summary #

  • Option<T> for absence, Result<T, E> for failureOption when absence of value is a normal condition; Result when a failure occurs due to an external condition that needs to be reported.
  • Avoid unwrap() in production codes — use unwrap_or, unwrap_or_else, or ? for safe handling. Save unwrap() for prototyping or testing.
  • ? operator for error propagation — much cleaner than repeated match. Make sure the function returns a compatible Result or Option, and implement From for automatic error type conversion.
  • map and and_then for chainingmap changes the value inside without changing Some/Ok vs None/Err; and_then for operations that themselves return Option or Result.
  • ok_or and ok_or_else for Option → Result conversion — useful when working in contexts that expect Result but the library function returns Option.
  • Custom error type with thiserror — for libraries, define an error enum with explicit variants to allow users to perform pattern matching. Use #[from] for automatic conversion.
  • anyhow for binary and application code — ergonomic, does not require detailed error type definitions, and supports rich error context via .context().
  • collect::<Result<Vec<_>, _>>() — idiomatic way to process collections where individual items can fail. Fail fast when an error occurs, or use filter_map to silently ignore errors.


← Previous: Math   Next: Iterators →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact