% Borrow e AsRef
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.