Semântica de Move e Cópia
Atribuição e passagem por valor movem (transferem propriedade) ou copiam (duplicam bits) dependendo do tipo. Clone fornece duplicação explícita quando necessário.
Receita
#[derive(Clone, Debug)]
struct Config { host: String, port: u16 }
fn main() {
let port: u16 = 8080; // Cópia
let p2 = port;
let cfg = Config { host: "localhost".into(), port };
let cfg2 = cfg.clone(); // cópia profunda explícita
println!("{port} {:?} {:?}", cfg, cfg2);
}Quando usar isso: Decidir se um tipo deve ser Copy, quando usar clone(), e projetar APIs que movem vs. emprestam.
Exemplo de Trabalho
#[derive(Copy, Clone, Debug)]
struct Point { x: i32, y: i32 }
fn translate(p: Point, dx: i32) -> Point {
Point { x: p.x + dx, y: p.y }
}
fn main() {
let origin = Point { x: 0, y: 0 };
let moved = origin; // Cópia - ambos válidos
let shifted = translate(moved, 5);
println!("{origin:?} {shifted:?}");
}O que isso demonstra:
PointéCopyporque todos os campos sãoCopyoriginpermanece utilizável após a atribuição- Pequenos agregados apenas na stack são bons candidatos a
Copy Stringnão pode serCopy(propriedade do heap)
Mergulho Profundo
Semântica de Move
- Atribuição não-
Copyinvalida o binding de origem - Moves são baratos para tipos de heap (cópia de ponteiro)
- Parâmetros de função por valor assumem propriedade, a menos que emprestados
Vec,String,HashMapsempre movem na atribuição
Requisitos de Copy
// Todos os campos Copy, sem impl Drop (geralmente)
#[derive(Copy, Clone)]
struct Flags(u32);Tipos com Drop customizado geralmente não podem ser Copy.
Clone vs Copy
| Trait | Quando | Efeito |
|---|---|---|
Copy | Implícito na atribuição | Duplicação bit a bit |
Clone | .clone() explícito | Duplicação definida pelo usuário |
Clone em Coleções
let v1 = vec![1, 2];
let v2 = v1.clone(); // clona elementos se T: CloneArmadilhas
- Derivar
Copyem struct comString- Erro de compilação. Correção: RemoverCopyou usar&str/Arc<str>se o compartilhamento for necessário. - Clonar em loops - Oculta problemas de desempenho. Correção: Reestruturar para emprestar ou reutilizar buffers.
- Assumir que a atribuição copia
Vec- Ela move. Correção: Usar.clone()explicitamente quando a duplicata for necessária. - Conflito
Copy+Drop-Dropcustomizado significa que a semântica de move importa. Correção: Não implementarCopy. - Move parcial e depois usa struct - Campos movidos invalidam o uso da struct inteira em alguns casos. Correção: Desestruturar ou emprestar campos.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
Empréstimo &T | Acesso compartilhado somente leitura | Chamador deve reter propriedade para retorno |
Rc/Arc | Propriedade compartilhada sem clone profundo | Um único proprietário é mais claro |
Cow<'a, T> | Às vezes empresta, às vezes possui | Sempre um modo |
| Move apenas | A transferência é intencional | Chamadores precisam continuar usando o valor |
FAQs
Move é um memcpy?
Para tipos Copy, sim. Para tipos de heap, move copia os metadados da stack (ponteiro, len, cap), não os dados do heap.
Posso implementar Copy manualmente?
Sim com unsafe impl Copy, mas derivar é o padrão. Todos os campos devem ser Copy previamente.
Clone sempre faz cópia profunda?
A semântica de Clone é definida pelo tipo. Arc::clone apenas incrementa a contagem de referências.
Por que i32 é Copy mas String não?
i32 está inteiramente na stack sem propriedade. String possui alocação no heap.
E os arrays?
[T; N] é Copy quando T: Copy. Arrays grandes são Copy mas caros para copiar bit a bit.
Move e inicialização parcial?
Use MaybeUninit em padrões unsafe. Código seguro usa valores totalmente inicializados.
O retorno move o valor?
Sim para tipos não-Copy. O otimizador pode elidir cópias na prática (NRVO).
Enums podem ser Copy?
Sim se os payloads de todas as variantes forem Copy.
Qual o custo de `#[derive(Clone)]`?
Derivar percorre os campos recursivamente. Campos de heap clonam seus conteúdos.
Move em tarefas async?
Dados de propriedade movem para futures. Bounds Send governam moves entre threads.
Relacionados
- Noções Básicas de Propriedade - regra de proprietário único
- Empréstimos e Referências - evitar moves
- Rc & Arc - propriedade compartilhada
- Cow - clone sob demanda
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.