Index în Rust

Trait-ul din spatele operatorului container[i]; IndexMut permite și container[i] = valoare.

Sintaxă
impl Index<Idx> for Tip {
    type Output = Element;
    fn index(&self, i: Idx) -> &Element { ... }
}

Ce face Index

v[i] este scurtătura pentru *v.index(i). Vec, tablourile, HashMap (doar citire) și String cu intervale (s[1..3]) implementează Index. Pentru tipurile tale îl implementezi alegând tipul indicelui (usize, &str, un enum) și tipul elementului (type Output).

index returnează o referință, nu o valoare, și nu are cum să returneze o eroare: prin convenție, un indice greșit oprește programul cu panică. Pentru un acces sigur oferă și o metodă get care returnează Option. Pentru scriere (c[i] = x) implementezi și IndexMut.

Parametri

Parametru Descriere
type Output Tipul elementului returnat.
index(&amp;self, i) Returnează &Output pentru indicele dat.

Ce returnează

&Self::Output (sau &mut pentru IndexMut).

Exemple

Exemplul 1: Catalog indexat după numele elevului

use std::ops::{Index, IndexMut};

struct Catalog {
    elevi: Vec<(String, Vec<u8>)>,
}

impl Index<&str> for Catalog {
    type Output = Vec<u8>;
    fn index(&self, nume: &str) -> &Vec<u8> {
        &self.elevi.iter().find(|(n, _)| n == nume).expect("elev inexistent").1
    }
}

impl IndexMut<&str> for Catalog {
    fn index_mut(&mut self, nume: &str) -> &mut Vec<u8> {
        &mut self.elevi.iter_mut().find(|(n, _)| n == nume).expect("elev inexistent").1
    }
}

fn main() {
    let mut c = Catalog {
        elevi: vec![("Ana".into(), vec![9, 10]), ("Radu".into(), vec![7])],
    };
    c["Radu"].push(9);
    println!("Ana: {:?}", c["Ana"]);
    println!("Radu: {:?}", c["Radu"]);
}

Rezultat

Ana: [9, 10]
Radu: [7, 9]

Exemplul 2: Indice de tip enum

use std::ops::Index;

#[derive(Clone, Copy)]
enum Zi {
    Luni,
    Marti,
    Miercuri,
}

struct Program {
    ore: [u8; 3],
}

impl Index<Zi> for Program {
    type Output = u8;
    fn index(&self, z: Zi) -> &u8 {
        &self.ore[z as usize]
    }
}

fn main() {
    let p = Program { ore: [6, 5, 7] };
    for (nume, zi) in [("luni", Zi::Luni), ("marți", Zi::Marti), ("miercuri", Zi::Miercuri)] {
        println!("{nume}: {} ore", p[zi]);
    }
}

Rezultat

luni: 6 ore
marți: 5 ore
miercuri: 7 ore

Greșeli frecvente

  • Încerci c[i] = x cu doar Index implementat: cannot assign to data in an index of `Catalog`. Implementează și IndexMut.
  • Returnezi o valoare în loc de referință din index: semnătura cere &Self::Output.

Comenzi înrudite

  • Add: Trait-ul din spatele operatorului +; implementându-l, poți aduna valori ale tipurilor tale (bani, vectori).
  • Deref: Trait-ul din spatele operatorului * și al conversiei automate &Box<T> -> &T, &String -> &str (deref coercion).
  • str: Tipul pentru o bucată de text UTF-8 împrumutată (&str): literalii, părți din String, parametrii de funcții.