Ce face write! și writeln!
write!(dest, ...) și writeln!(dest, ...) au aceeași sintaxă ca print! și println!, dar scriu în dest. Destinația trebuie să implementeze fie std::fmt::Write (de exemplu String), fie std::io::Write (fișiere, stdout(), Vec<u8>, BufWriter). Trait-ul potrivit trebuie importat cu use.
Spre deosebire de println!, ele returnează un Result, pentru că scrierea poate eșua (disc plin, conexiune închisă). Îl tratezi cu ?, cu unwrap() sau îl verifici; dacă îl ignori, compilatorul avertizează unused `Result` that must be used.
În implementarea trait-ului Display (fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result), write!(f, ...) este modul obișnuit de a produce textul. Pentru a adăuga mult text într-un String, write! este mai eficient decât format! repetat, pentru că nu creează texte intermediare.
Ce returnează
fmt::Result (pentru fmt::Write) sau io::Result<()> (pentru io::Write).
Exemple
Exemplul 1: Construirea unui raport într-un String
Cu std::fmt::Write importat, String poate fi destinația lui writeln!. Textul crește pe loc, fără texte intermediare.
use std::fmt::Write;
fn main() {
let elevi = [("Ana", 9.45), ("Mihai", 8.1), ("Ioana", 9.9)];
let mut raport = String::new();
writeln!(raport, "Raport clasa a X-a").unwrap();
for (i, (nume, media)) in elevi.iter().enumerate() {
writeln!(raport, "{}. {nume:<6} {media:.2}", i + 1).unwrap();
}
write!(raport, "Total elevi: {}", elevi.len()).unwrap();
println!("{raport}");
}
Rezultat
Raport clasa a X-a
1. Ana 9.45
2. Mihai 8.10
3. Ioana 9.90
Total elevi: 3
Exemplul 2: Scrierea într-un fișier, cu ?
Cu std::io::Write, destinația este un fișier creat în directorul curent. Fiecare writeln! poate eșua, deci folosim ?, iar main returnează io::Result.
use std::fs::{self, File};
use std::io::{self, BufWriter, Write};
fn main() -> io::Result<()> {
let mut fisier = BufWriter::new(File::create("temperaturi.csv")?);
writeln!(fisier, "oras,grade")?;
for (oras, grade) in [("Iași", 21.5), ("Suceava", 18.0)] {
writeln!(fisier, "{oras},{grade}")?;
}
fisier.flush()?;
print!("{}", fs::read_to_string("temperaturi.csv")?);
Ok(())
}
Rezultat
oras,grade
Iași,21.5
Suceava,18
Exemplul 3: write! în implementarea lui Display
f este destinația dată de println!. Ce scrie write! în f apare acolo unde este folosit {}. Opțiunile de formatare se pot transmite mai departe ({:02}).
use std::fmt;
struct Ora {
ore: u8,
minute: u8,
}
impl fmt::Display for Ora {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02}:{:02}", self.ore, self.minute)
}
}
fn main() {
let tren = Ora { ore: 7, minute: 5 };
println!("Trenul Iași–București pleacă la {tren}");
let text = format!("[{tren}]");
println!("{text}");
}
Rezultat
Trenul Iași–București pleacă la 07:05
[07:05]
Greșeli frecvente
- Uiți să imporți trait-ul:
cannot write into `String`cu sugestiause std::fmt::Write. Pentru fișiere ai nevoie destd::io::Write. - Imporți ambele trait-uri
Writeîn același fișier: conflict de nume. Foloseșteuse std::fmt::Write as FmtWrite;sauuse std::io::{self, Write};șistd::fmt::Writeprin cale completă. - Ignori rezultatul lui
write!pe un fișier: o eroare de scriere trece neobservată. Folosește?. - Folosești
println!înfmtîn loc dewrite!(f, ...): textul ajunge direct pe ecran, nu în locul unde a fost cerut (de exemplu într-unformat!).
Comenzi înrudite
format! (și sintaxa de formatare): Construiește un String nou din șablon și valori, cu aceeași sintaxă ca println!, dar fără să afișeze nimic.println! și print!: Afișează text pe ieșirea standard: println! adaugă la final un rând nou, print! nu. Acoladele {} sunt înlocuite cu valori.format_args!: Pregătește un text formatat fără să-l construiască: produce un fmt::Arguments care poate fi scris oriunde, fără alocare.operatorul ?: Pus după un Result sau Option: dă valoarea dacă totul e bine, altfel returnează imediat eroarea (sau None) din funcția curentă.use: Aduce în domeniu un nume dintr-un modul sau crate (std::collections::BTreeMap), ca să-l poți folosi fără calea completă.