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.