Tipos asociados

El uso de "tipos asociados" mejora la legibilidad general del código al mover los tipos internos localmente a un rasgo como tipos de salida. La sintaxis de la definición de trait es la siguiente:


#![allow(unused)]
fn main() {
// `A` y `B` se definen en el rasgo mediante la palabra clave `type`.
// (Nota: `type` en este contexto es diferente de `type` cuando se usa para aliases).
trait Contiene {
    type A;
    type B;

    // Sintaxis actualizada para hacer referencia a estos nuevos tipos de forma genérica
    fn contiene(&self, &Self::A, &Self::B) -> bool;
}
}

Ten en cuenta que las funciones que usan el trait Contiene ya no son necesarias para expresar A o B en absoluto:

// Sin usar tipos asociados
fn diferencia<A, B, C>(contenedor: &C) -> i32 where
    C: Contiene<A, B> { ... }

// Usando tipos asociados
fn diferencia<C: Contiene>(contenedor: &C) -> i32 { ... }

Reescribamos el ejemplo de la sección anterior usando tipos asociados:

struct Contenedor(i32, i32);

// Un rasgo que comprueba si hay 2 elementos almacenados dentro del contenedor.
// También recupera el primer o último valor.
trait Contiene {
  // Define aquí los tipos genéricos que métodos podrán utilizar.
    type A;
    type B;

    fn contiene(&self, _: &Self::A, _: &Self::B) -> bool;
    fn primer(&self) -> i32;
    fn ultimo(&self) -> i32;
}

impl Contiene for Contenedor {
    // Especifica los tipos `A` y `B`. Si el tipo de `entrada` es `Contenedor(i32, i32)`
    // se determinan los tipos de `salida` como `i32` y` i32`.
    type A = i32;
    type B = i32;

    // `&Self::A` y `&Self::B` también son válidos aquí.
    fn contiene(&self, numero_1: &i32, numero_2: &i32) -> bool {
        (&self.0 == numero_1) && (&self.1 == numero_2)
    }
    // Coge el primer número.
    fn primer(&self) -> i32 { self.0 }

    // Coge el último número.
    fn ultimo(&self) -> i32 { self.1 }
}

fn diferencia<C: Contiene>(contenedor: &C) -> i32 {
    contenedor.ultimo() - contenedor.primer()
}

fn main() {
    let numero_1 = 3;
    let numero_2 = 10;

    let contenedor = Contenedor(numero_1, numero_2);

    println!("Contenedor contiene {} y {}: {}",
        &numero_1, &numero_2,
        contenedor.contiene(&numero_1, &numero_2));
    println!("Primer número: {}", contenedor.primer());
    println!("Último número: {}", contenedor.ultimo());
    
    println!("La diferencia es: {}", diferencia(&contenedor));
}