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.

trait Describible {
    fn descriure(&self) -> String;
}

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

  1. Defineix un trait anomenat Calculable amb un mètode calcular que retorna un i32.
  2. Implementa el trait Calculable per a una struct Rectangle amb camps ample i alt.
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

  1. Defineix una funció genèrica imprimir_calcul que accepti qualsevol tipus que implementi el trait Calculable i imprimeixi el resultat del mètode calcular.
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.

© Copyright 2024. Tots els drets reservats