No capítulo sobre tipos por valor, resumimos o comportamento padrão do Swift como “cópia”: atribuir copia, e passar para uma função também copia.
Este conteúdo dá continuidade ao artigo anterior Swift avançado #7.
Mas e se existirem valores que não podem ser copiados? Recursos que só fazem sentido quando há “exatamente um no mundo”, como identificadores de arquivo, locks de mutex e tokens de transferência bancária.
O tema desta edição da série avançada é propriedade (ownership). O ~Copyable do Swift 5.9 (tipos não copiáveis), borrowing e consuming abrem essa porta. SE-0390: Noncopyable Structs and Enums
Quem conhece Rust vai reconhecer a ideia. Sim: o Swift importou os conceitos centrais do Rust à sua maneira.
Mas a direção é diferente. No Rust, propriedade é o padrão e não há exceções; no Swift, cópia é o padrão e propriedade é uma ferramenta opcional.
A lacuna de um mundo em que copiar é o padrão
Todos os tipos do Swift são Copyable por padrão. Mesmo sem declarar isso, o compilador faz a adoção implícita do protocolo.
É daí que vem a semântica de cópia de atribuições e passagens vista no capítulo de tipos por valor. Para a maioria dos valores — números, strings e coordenadas — é um padrão perfeito.
O problema está nos tipos que representam recursos. Pense em um struct que envolve um descritor de arquivo.
struct FileHandle {
let fd: Int32
func close() { /* fd Fechar */ }
}
let a = FileHandle(fd: open("data.txt"))
let b = a // Cópia — agora dois conhecem o mesmo fd
a.close()
b.close() // Fechar novamente um fd já fechado — comportamento indefinido
No momento em que o identificador é copiado, fica ambíguo “quem é responsável por fechá-lo”. A cópia indevida está na raiz de bugs de recursos, como liberação dupla e uso de identificadores fechados.
A solução tradicional era usar uma classe e fechar em deinit, centralizando o gerenciamento em uma única referência.
Funciona, mas há os custos vistos no capítulo sobre ARC (Automatic Reference Counting, contagem automática de referências): heap e contagem de referências.
Além disso, o compilador ainda não conhece a regra “não pode copiar”.
~Copyable — gravando a não copiabilidade no tipo
A resposta do Swift 5.9 são os tipos não copiáveis (proposta Swift Evolution SE-0390). O ~Copyable com til é uma declaração de que “não adota Copyable”. SE-0390: Noncopyable Structs and Enums
struct FileHandle: ~Copyable {
let fd: Int32
consuming func close() { /* fd Fechar */ }
deinit { /* Fechar aqui se ainda não tiver sido fechado */ }
}
let a = FileHandle(fd: open("data.txt"))
let b = a // Não é cópia, é movimento — a propriedade passa para b
// print(a.fd) // Erro de compilação: a já foi consumido
O comportamento muda fundamentalmente. A atribuição passa a ser um movimento (move), não uma cópia, e a variável cuja propriedade foi transferida não pode mais ser usada.
A violação gera um erro de compilação, não um crash em runtime. O compilador mantém um registro da regra de que “este valor sempre tem exatamente um proprietário”.
Assim como Optional transformou nil e Sendable transformou condições de corrida em problemas de tipo, a unicidade dos recursos também vira um problema de tipo.
Há ainda um bônus: um struct pode declarar deinit, então a limpeza determinística é executada quando o proprietário sai do escopo.
Isso permite gerenciamento de recursos no estilo RAII (Resource Acquisition Is Initialization) sem classes.
borrowing e consuming — três formas de passar valores para funções
Ao passar um valor não copiável para uma função, surge uma nova pergunta. Como não é possível copiá-lo, você precisa decidir se vai emprestá-lo ou transferi-lo.
Os modificadores de parâmetro expressam essa escolha.
borrowing significa empréstimo. A função apenas lê o valor, e a propriedade continua com o chamador.
O chamador pode continuar usando o valor depois que a função retorna. func checksum(of handle: borrowing FileHandle) -> Int É o lugar de operações somente de leitura como esta.
consuming significa transferência. A propriedade passa para a função, e o chamador não pode mais usar o valor. O consuming func close() acima tem exatamente esse significado.
Usar o identificador depois de chamar close vira um erro de compilação. É o momento em que a classe de bugs “usar novamente um identificador fechado” desaparece da sintaxe.
Também é uma ferramenta para modelar conceitos de domínio que devem desaparecer quando usados, como tokens de transferência bancária e tickets de uso único.
inout mantém o comportamento conhecido: emprestar e modificar. Juntos, os três completam o vocabulário de propriedade dos parâmetros: apenas ler (borrowing), levar (consuming) e modificar (inout).
Esses modificadores também podem ser usados em tipos Copyable. Nesse caso, funcionam como dicas de desempenho, não como semântica.
Eles substituem retain/release ou cópias que podem surgir da convenção padrão por empréstimos e movimentos, reduzindo o tráfego de ARC. Exigir movimento explícito com o operador consume (let b = consume a) pertence à mesma família.
Mas esta é uma área de micro-otimização que exige medição antes. O alerta sobre a conveniência do dispatch também se aplica aqui.
Na prática — onde usar e onde não usar
É importante entender exatamente qual é a posição atual desse recurso.
Ele é adequado para propriedade única de recursos. Por exemplo, wrappers de identificadores de arquivo e socket, tokens de lock, guards de transação e direitos de acesso ao hardware.
Na prática, um dos principais impulsionadores desse recurso foi o Embedded Swift. Em microcontroladores, heap e ARC são pesados, então era necessário gerenciar recursos com segurança sem classes.
Os valores fornecidos pelo Mutex da biblioteca padrão e tipos recentes como Span seguem essa linhagem.
O padrão para código de aplicativos comuns continua sendo struct Copyable. O princípio orientado a valores permanece.
Aplicar ~Copyable antecipadamente aos dados de domínio é overengineering. Ainda existe atrito com o ecossistema de genéricos: tipos não copiáveis não se misturam diretamente com genéricos e coleções existentes que assumem Copyable, e a linguagem está resolvendo isso gradualmente.
Por enquanto, use-o como ferramenta especializada apenas em tipos para os quais a resposta a “copiar seria um bug?” é sim.
Para concluir com uma comparação com Rust, Rust é uma linguagem de “propriedade por padrão” que impõe regras de propriedade a todos os valores e exige até anotações de lifetime.
O Swift mantém o mundo em que copiar é o padrão e leva apenas os tipos necessários para o mundo da propriedade: “propriedade opcional”.
É um exemplo clássico de Progressive Disclosure. O código de quem não conhece propriedade nem contém esse conceito; a próxima etapa se abre apenas para quem precisa dela.
Resumo
- Todos os tipos são implicitamente Copyable, e a cópia indevida de tipos de recursos está na raiz de bugs de liberação dupla e semelhantes.
- ~Copyable (SE-0390) proíbe cópias, transforma atribuições em movimentos e faz do uso de uma variável consumida um erro de compilação. Também permite deinit em structs para limpeza determinística.
- Vocabulário de propriedade dos parâmetros: borrowing (apenas ler, empréstimo), consuming (levar, transferência) e inout (modificar). Métodos consuming registram na sintaxe o significado de “desaparece quando usado”.
- Use-o para propriedade única de recursos — identificadores, locks, tokens e sistemas embarcados — enquanto structs Copyable continuam sendo o padrão para dados comuns. Diferentemente da propriedade universal do Rust, o Swift usa propriedade opcional.
O próximo artigo é o último tema da série avançada e de toda a série Swift: a história por trás de “o tamanho do app caiu de repente no Swift 5”, a estabilidade do ABI (Application Binary Interface). SE-0390: Noncopyable Structs and Enums
Fontes e critérios de verificação
- SE-0390: Noncopyable Structs and Enums — Swift Evolution · texto original de padrões e especificações · verificado em 2026-08-17 · base: ~Copyable, consuming, borrowing e regras de tipos não copiáveis do Swift 5.9

![Imagem de capa de [Swift avançado #8] ~Copyable, propriedade e tipos não copiáveis](/assets/images/posts/d9a5f7c8-fa35-4590-aca1-b3e4e60f6a6b/swift-noncopyable-ownership-move.jpg)