Els traits són una característica fonamental de Rust que permeten definir comportaments compartits entre diferents tipus. Són similars a les interfícies en altres llenguatges de programació com Java o C#. En aquest tema, aprendrem què són els traits, com definir-los, com implementar-los i com utilitzar-los en el nostre codi.
Què és un Trait?
Un trait és una col·lecció de mètodes que poden ser implementats per diferents tipus. Els traits permeten definir funcionalitats comunes que poden ser compartides per múltiples tipus, assegurant que aquests tipus implementin certs comportaments.
Definició d'un Trait
Per definir un trait, utilitzem la paraula clau trait seguida del nom del trait i el bloc de mètodes que defineixen el comportament.
En aquest exemple, hem definit un trait anomenat Describible amb un mètode descriure que retorna una String.
Implementació d'un Trait
Per implementar un trait per a un tipus específic, utilitzem la paraula clau impl seguida del nom del trait per al tipus.
struct Persona {
nom: String,
edat: u32,
}
impl Describible for Persona {
fn descriure(&self) -> String {
format!("{} té {} anys.", self.nom, self.edat)
}
}En aquest exemple, hem implementat el trait Describible per a la struct Persona. El mètode descriure retorna una descripció de la persona.
Ús d'un Trait
Un cop hem implementat un trait per a un tipus, podem utilitzar els mètodes del trait en instàncies d'aquest tipus.
fn main() {
let persona = Persona {
nom: String::from("Joan"),
edat: 30,
};
println!("{}", persona.descriure());
}Aquest codi crearà una instància de Persona i cridarà el mètode descriure, imprimint la descripció de la persona.
Traits i Generics
Els traits són especialment útils quan es combinen amb generics. Podem utilitzar traits per restringir els tipus que es poden passar a una funció o struct genèrica.
Funcions Genèriques amb Traits
Podem definir funcions genèriques que accepten qualsevol tipus que implementi un trait específic.
fn imprimir_descripcio<T: Describible>(item: T) {
println!("{}", item.descriure());
}
fn main() {
let persona = Persona {
nom: String::from("Joan"),
edat: 30,
};
imprimir_descripcio(persona);
}En aquest exemple, la funció imprimir_descripcio accepta qualsevol tipus T que implementi el trait Describible.
Structs Genèriques amb Traits
De manera similar, podem definir structs genèriques que accepten qualsevol tipus que implementi un trait específic.
struct Caixa<T: Describible> {
element: T,
}
impl<T: Describible> Caixa<T> {
fn nova(element: T) -> Caixa<T> {
Caixa { element }
}
fn descriure_element(&self) -> String {
self.element.descriure()
}
}
fn main() {
let persona = Persona {
nom: String::from("Joan"),
edat: 30,
};
let caixa = Caixa::nova(persona);
println!("{}", caixa.descriure_element());
}En aquest exemple, hem definit una struct genèrica Caixa que accepta qualsevol tipus T que implementi el trait Describible.
Exercicis Pràctics
Exercici 1: Definir i Implementar un Trait
- Defineix un trait anomenat
Calculableamb un mètodecalcularque retorna uni32. - Implementa el trait
Calculableper a una structRectangleamb campsampleialt.
trait Calculable {
fn calcular(&self) -> i32;
}
struct Rectangle {
ample: i32,
alt: i32,
}
impl Calculable for Rectangle {
fn calcular(&self) -> i32 {
self.ample * self.alt
}
}
fn main() {
let rectangle = Rectangle { ample: 5, alt: 10 };
println!("Àrea del rectangle: {}", rectangle.calcular());
}Exercici 2: Funcions Genèriques amb Traits
- Defineix una funció genèrica
imprimir_calculque accepti qualsevol tipus que implementi el traitCalculablei imprimeixi el resultat del mètodecalcular.
fn imprimir_calcul<T: Calculable>(item: T) {
println!("Resultat del càlcul: {}", item.calcular());
}
fn main() {
let rectangle = Rectangle { ample: 5, alt: 10 };
imprimir_calcul(rectangle);
}Resum
En aquest tema, hem après què són els traits en Rust, com definir-los, implementar-los i utilitzar-los. També hem vist com combinar traits amb generics per crear funcions i structs més flexibles i reutilitzables. Els traits són una eina poderosa per definir comportaments compartits i assegurar que els tipus implementin certs mètodes, facilitant la creació de codi modular i mantenible.
