comentarii și documentație (//, ///, //!) în Rust

// și /* */ sunt comentarii obișnuite; /// și //! scriu documentație Markdown, transformată în HTML de cargo doc și testată de cargo test.

Sintaxă
// comentariu pe o linie
/* comentariu pe
   mai multe linii */
/// documentația elementului de dedesubt (Markdown)
//! documentația modulului sau crate-ului în care se află

Ce face comentarii și documentație (//, ///, //!)

// începe un comentariu până la sfârșitul liniei, iar /* ... */ poate cuprinde mai multe linii (și se poate imbrica). Compilatorul le ignoră complet. În Rust se preferă // chiar și pentru mai multe linii.

/// scrie documentația elementului de dedesubt (funcție, structură, câmp, metodă), în Markdown. //! documentează elementul care îl conține, de obicei tot crate-ul (la începutul lui lib.rs) sau un modul. cargo doc --open transformă aceste comentarii într-un site HTML, ca cel de pe docs.rs.

Blocurile de cod dintr-un comentariu /// sunt doctests: cargo test le compilează și le rulează ca teste, deci exemplele din documentație nu se pot învechi. Prin convenție, documentația are secțiuni ca # Examples, # Panics, # Errors și # Safety (pentru funcțiile unsafe).

Exemple

Exemplul 1: Toate felurile de comentarii

Programul se compilează și rulează normal: comentariile nu schimbă nimic. Comentariile /// ar apărea în documentația generată cu cargo doc.

//! Calculator de dobândă simplă, exemplu pentru dexblog.ro.

/// Un depozit bancar.
struct Depozit {
    /// Suma inițială, în lei.
    suma: f64,
    /// Dobânda anuală, în procente (de exemplu 6.5).
    dobanda: f64,
}

impl Depozit {
    /// Calculează suma după `ani` ani, cu dobândă compusă.
    fn valoare_dupa(&self, ani: u32) -> f64 {
        // la fiecare an, suma crește cu dobânda
        self.suma * (1.0 + self.dobanda / 100.0).powi(ani as i32)
    }
}

fn main() {
    let d = Depozit { suma: 10_000.0, dobanda: 6.5 };
    /* afișăm câțiva ani
       ca să vedem cum crește suma */
    for ani in [1, 5, 10] {
        println!("după {ani:>2} ani: {:.2} lei", d.valoare_dupa(ani));
    }
}

Rezultat

după  1 ani: 10650.00 lei
după  5 ani: 13700.87 lei
după 10 ani: 18771.37 lei

Exemplul 2: Documentație cu exemplu testat (doctest)

Biblioteca calcule are o funcție documentată cu un exemplu. cargo test rulează testele obișnuite și apoi, la „Doc-tests”, exemplul din documentație.

// src/lib.rs
/// Calculează media notelor, rotunjită la două zecimale.
///
/// ```
/// let m = calcule::media(&[9.0, 10.0, 8.0]);
/// assert_eq!(m, Some(9.0));
/// ```
pub fn media(note: &[f64]) -> Option<f64> {
    if note.is_empty() {
        return None;
    }
    let suma: f64 = note.iter().sum();
    Some((suma / note.len() as f64 * 100.0).round() / 100.0)
}

$ cargo test

Rezultat în terminal

   Compiling calcule v0.1.0 (/home/ana/proiecte/calcule)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.71s
     Running unittests src/lib.rs (target/debug/deps/calcule-0416c878abb4e129)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests calcule

running 1 test
test src/lib.rs - media (line 3) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

all doctests ran in 0.64s; merged doctests compilation took 0.35s

Greșeli frecvente

  • Pui /// deasupra unei instrucțiuni din corpul funcției: compilatorul avertizează unused doc comment. În interiorul funcțiilor folosește //.
  • Lași în documentație exemple care nu se mai compilează. Ele sunt teste: cargo test le rulează și le raportează ca eșuate. Pentru cod care nu trebuie rulat, marchează blocul cu ```ignore sau ```no_run.
  • Comentezi ce face codul, rând cu rând (// adun 1 la i). Comentariile utile explică de ce; ce face codul se vede din cod.

Comenzi înrudite

  • cargo doc: Generează documentația HTML a proiectului din comentariile ///, cu toate tipurile și funcțiile publice, ca pe docs.rs.
  • teste (#[test]): O funcție marcată cu #[test] este un test automat: cargo test o rulează și raportează dacă a trecut sau a dat panică.
  • atribute (#[derive], #[cfg], #[allow]): Informații pentru compilator scrise cu #[…] deasupra unui element: generează cod (derive), aleg codul compilat (cfg) sau schimbă avertismentele.
  • cargo test: Compilează proiectul în mod test și rulează toate testele: cele #[test], testele din tests/ și exemplele din documentație.