I tratti Borrow e AsRef sono molto simili, ma diversi.
Ecco un rapido ripasso di quello che questi due tratti significano.
Il tratto Borrow si usa quando si sta scrivendo una struttura dati,
e, per qualche scopo, si vuole usare come sinonimo un tipo o posseduto
o preso in prestito.
Per esempio, HashMap ha un metodo get che usa Borrow:
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
Questa firma è parecchio complicata. Quello che ci interessa qui è
il parametro K. Si riferisce a un parametro di HashMap stesso:
struct HashMap<K, V, S = RandomState> {
Il parametro K è il tipo della chiave usata da HashMap. Quindi,
riguardando la firma di get(), vediamo che possiamo usareget() quando
la chiave implementa Borrow<Q>. In quel modo, possiamo costruire
un HashMap che usa chiavi String, ma usare delle &str quando cerchiamo:
use std::collections::HashMap; let mut map = HashMap::new(); map.insert("Foo".to_string(), 42); assert_eq!(map.get("Foo"), Some(&42));
Questo perché la libreria standard ha impl Borrow<str> for String.
Per la maggior parte dei tipi, quando si vuole prenderne un tipo posseduto
o preso in prestito, un &T può bastare. Ma un'area dove Borrow è efficace
è quando c'è più di un genere di valore preso in prestito. Ciò è vero
specialmente per i riferimenti e le slice: si può avere sia un &T
che un &mut T. Se vogliamo accettare entrambi questi tipi, Borrow è
quel che ci vuole:
use std::borrow::Borrow; use std::fmt::Display; fn foo<T: Borrow<i32> + Display>(a: T) { println!("a è preso in prestito: {}", a); } let mut i = 5; foo(&i); foo(&mut i);
Questo stamperà due volte a è preso in prestito: 5.
Il tratto AsRef è un tratto di conversione. Serve a convertire
qualche valore in un riferimento nel codice generico. Così:
let s = "Hello".to_string(); fn foo<T: AsRef<str>>(s: T) { let slice = s.as_ref(); }
Come si vede, sono in qualche modo uguali: entrambi trattano versioni possedute o prese in prestito di qualche tipo. Però, sono un po' diversi.
Si scelga Borrow quando si vuole astrarre su diversi generi di prestiti,
oppure quando si sta costruendo una struttura dati che tratta i valori
posseduti e i valori presi in prestito in modi equivalenti, come lo hashing
e il confronto.
Si scelga AsRef quando si vuole convertire qualcosa direttamente
a un riferimento, e si sta scrivendo del codice generico.