AsRef în Rust

Conversie ieftină de la referință la referință; folosit în funcții generice care acceptă String, &str, PathBuf etc.

Sintaxă
pub trait AsRef<T: ?Sized> {
    fn as_ref(&self) -> &T;
}

fn f<P: AsRef<Path>>(cale: P) { let p: &Path = cale.as_ref(); }

Ce face AsRef

AsRef<T> înseamnă „din mine poți obține ieftin un &T”. String, &str și Box<str> implementează AsRef<str>; Vec<T> și tablourile implementează AsRef<[T]>; String, &str, PathBuf și &Path implementează AsRef<Path>.

Așa sunt scrise funcțiile din std::fs: fs::read_to_string<P: AsRef<Path>>(path: P) primește orice fel de cale. În funcțiile tale îl folosești la fel: parametrul generic, apoi .as_ref() în corp. Conversia nu copiază nimic; spre deosebire de Into, nu creează o valoare nouă.

Ce returnează

as_ref() returnează &T.

Exemple

Exemplul 1: O funcție pentru orice fel de text

fn numar_cuvinte<S: AsRef<str>>(text: S) -> usize {
    text.as_ref().split_whitespace().count()
}

fn main() {
    let deținut = String::from("Ana are mere și pere");
    println!("{}", numar_cuvinte("Bună ziua, Iași"));
    println!("{}", numar_cuvinte(&deținut));
    println!("{}", numar_cuvinte(deținut));
}

Rezultat

3
5
5

Exemplul 2: Căi și felii

use std::path::{Path, PathBuf};

fn extensie<P: AsRef<Path>>(cale: P) -> String {
    match cale.as_ref().extension() {
        Some(e) => e.to_string_lossy().into_owned(),
        None => String::from("(fără)"),
    }
}

fn suma<V: AsRef<[u32]>>(valori: V) -> u32 {
    valori.as_ref().iter().sum()
}

fn main() {
    println!("{}", extensie("raport.pdf"));
    println!("{}", extensie(String::from("poze/vara.jpg")));
    println!("{}", extensie(PathBuf::from("/etc/hosts")));
    println!("{} {}", suma([1, 2, 3]), suma(vec![10, 20]));
}

Rezultat

pdf
jpg
(fără)
6 30

Greșeli frecvente

  • Folosești AsRef când ai nevoie de o valoare deținută. as_ref dă doar o referință; pentru o valoare nouă folosește Into.
  • Te aștepți ca AsRef să fie folosit automat ca Deref. Nu este: trebuie să apelezi explicit .as_ref().

Comenzi înrudite

  • Into: Perechea lui From văzută din partea sursei: x.into() convertește în tipul cerut; util în parametri generici.
  • Deref: Trait-ul din spatele operatorului * și al conversiei automate &Box<T> -> &T, &String -> &str (deref coercion).
  • From: Trait-ul pentru conversii care nu pot eșua: Tinta::from(x). Implementându-l, primești gratuit și x.into().