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
Calculable
amb un mètodecalcular
que retorna uni32
. - Implementa el trait
Calculable
per a una structRectangle
amb campsample
ialt
.
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_calcul
que accepti qualsevol tipus que implementi el traitCalculable
i 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.