Implementação do Trait Clone em Estruturas Recursivas e Objetos de Trait

Em Rust, o trait Clone permite a criação de duplicatas explícitas de objetos. Embora tipos simples possam derivar essa funcionalidade automaticamente, esrtuturas complexas que utilizam Box<T> ou objetos de trait (dyn Trait) exigem uma abordagem mais detalhada para garantir cópias profundas e corretas.

Clonagem em Estruturas Recursivas com Box<T>

Ao lidar com estruturas de dados recursivas, como listas encadeadas ou árvores, utilizamos o Box<T> para alocação no heap. Para implementar o Clone manualmente nessas estruturas, devemos processar recursivamente cada nó encapsulado.

use std::fmt;

struct Elemento {
    codigo: u32,
    filho: Option<box>,
}

impl fmt::Display for Elemento {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[Id: {}]", self.codigo)?;
        if let Some(ref proximo) = self.filho {
            write!(f, " -> {}", proximo)?;
        } else {
            write!(f, " -> FIM")?;
        }
        Ok(())
    }
}

impl Clone for Elemento {
    fn clone(&self) -> Self {
        Self {
            codigo: self.codigo,
            filho: self.filho.as_ref().map(|e| Box::new(*(e.clone()))),
        }
    }
}

fn main() {
    let e1 = Elemento { codigo: 10, filho: None };
    let e2 = Elemento { codigo: 20, filho: Some(Box::new(e1)) };
    
    let mut original = Elemento { codigo: 30, filho: Some(Box::new(e2)) };
    let copia = original.clone();

    // Modificando o valor original para provar a independência da cópia
    original.codigo = 99;

    println!("Original: {}", original);
    println!("Cópia:    {}", copia);
}
</box>

Clonagem de Objetos de Trait (dyn Trait)

Rust não permite que traits que possuam o trait Clone como super-trait sejam usados como objetos de trait (dyn Trait), porque o Clone requer que o tipo seja Sized. Para contornar essa limitação, utilizamos um padrão de "Clone Helper".

use std::fmt;

// Trait base com um requisito de clonagem customizado
trait Renderizavel: RenderizavelClone + fmt::Display {
    fn renderizar(&self);
}

// Helper para permitir a clonagem do Box contendo o trait
trait RenderizavelClone {
    fn duplicar_box(&self) -> Box<dyn Renderizavel>;
}

// Implementação genérica para qualquer tipo que já seja Clone e Renderizavel
impl<T> RenderizavelClone for T
where
    T: 'static + Renderizavel + Clone,
{
    fn duplicar_box(&self) -> Box<dyn Renderizavel> {
        Box::new(self.clone())
    }
}

// Agora podemos implementar Clone para o Box do Trait Object
impl Clone for Box<dyn Renderizavel> {
    fn clone(&self) -> Box<dyn Renderizavel> {
        self.duplicar_box()
    }
}

#[derive(Clone)]
struct Camada {
    nivel: i32,
    conteudo: Option<box renderizavel="">,
}

impl Renderizavel for Camada {
    fn renderizar(&self) {
        println!("Renderizando camada {}", self.nivel);
    }
}

impl fmt::Display for Camada {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Camada({})", self.nivel)?;
        if let Some(ref item) = self.conteudo {
            write!(f, " contém: {}", item)?;
        }
        Ok(())
    }
}

fn main() {
    let sub_camada = Camada { nivel: 1, conteudo: None };
    let mut principal = Camada {
        nivel: 2,
        conteudo: Some(Box::new(sub_camada)),
    };

    let copia_principal = principal.clone();
    principal.nivel = 5;

    println!("Original: {}", principal);
    println!("Cópia:    {}", copia_principal);
}
</box>

Esta técnica permite que estruturas que armazenam tipos dinâmicos via Box<dyn Trait> mantenham a capacidade de serem duplicadas integralmente, respeitando as regras de segurança de tipos do Rust.

Tags: Rust memory-management traits pointers

Publicado em 7-14 19:03