blense.
InícioFrontendProgramaçãoIANotíciasGuiasCheatsheetsSobre

Tecnologia decodificada, sempre.

Uma leitura curada sobre IA, produto e a cultura por trás do código. Sem ruído, sem hype.

blense.

Tecnologia com foco. Histórias sobre o que a inovação realmente muda.

Seções

FrontendInteligência ArtificialProgramação & DevNotícias Tech

Blense

SobreRSSPolítica de privacidadeTermosCookies
© 2026 Blense · blense.fun
Programação & Dev

Gerenciamento de memória no Rust: ownership, borrowing e lifetimes sem mistério

C te dá controle total — e uma arma apontada pro próprio pé. Go resolve com Garbage Collector — e picos de latência imprevisíveis. O Rust encontrou um terceiro caminho: segurança de memória garantida pelo compilador, sem custo em runtime.

Gpor Genildo Souza20 de mar.5 min de leitura
Gerenciamento de memória no Rust: ownership, borrowing e lifetimes sem mistério

O problema que cada linguagem resolve diferente

Toda linguagem precisa responder a uma pergunta fundamental: quando a memória que um valor ocupava pode ser liberada? A resposta define tudo — performance, segurança, previsibilidade.

Arsenal do dev de elite.
O fim do Virtual DOM: por que os Signals do SolidJS garantem performance O(1) sem re-renderizações10 minMicrofrontends com Angular e Nx: o que ninguém conta16 minComo escolher um SDK de IA: por que o medo de lock-in é um erro e como decidir pelo formato do seu app1 minFim do subsídio no Claude Agent SDK: prepare seu orçamento para um aumento de 15x a 30x nos custos de IA15 min
C / C++ — controle manual

Você aloca e libera. Máxima performance, máxima responsabilidade. Esqueceu um free(): memory leak. Liberou duas vezes: double-free. Acessou depois de liberar: use-after-free. 70% das vulnerabilidades da Microsoft vieram daqui.

Go — Garbage Collector

O runtime decide. Você não gerencia memória — o GC varre e libera o que não está mais em uso. Seguro, mas com custo: pausas periódicas imprevisíveis. O Discord migrou porque o GC causava picos a cada 2 minutos.

Rust — Ownership

O compilador decide. Regras verificadas em tempo de compilação garantem que a memória seja liberada exatamente quando deve — sem GC, sem gerenciamento manual, sem surpresas em runtime.

Ownership: cada valor tem um dono

O sistema de ownership do Rust tem três regras simples. Toda a segurança de memória da linguagem deriva delas.

1
Cada valor tem exatamente um dono

Uma variável é a dona do valor que ela armazena. Não existe valor sem dono.

2
Só pode existir um dono por vez

Quando você atribui um valor a outra variável, a propriedade se transfere — a variável original deixa de ser válida.

3
Quando o dono sai de escopo, o valor é liberado

Sem GC, sem free(). O compilador insere a liberação automaticamente quando a variável deixa de existir.

Na prática, isso fica assim:

JAVASCRIPT
let s1 = String::from("blueprint");let s2 = s1; // ownership se transfere pra s2println!("{}", s1); // ❌ erro de compilação: s1 não é mais válidaprintln!("{}", s2); // ✅ s2 é a nova dona

Em C ou Go, esse código funcionaria — e você teria dois ponteiros apontando pro mesmo dado na memória. Em Rust, o compilador recusa na hora. Não existe chance de double-free ou uso acidental de um valor já transferido.

ℹ️

Por que String e não &str? Tipos que vivem na stack (como inteiros) são copiados automaticamente — são baratos o suficiente. Tipos que vivem na heap (como String) transferem ownership. Se você quer copiar uma String, precisa chamar .clone() explicitamente — o que deixa o custo da operação visível no código.

Borrowing: usar sem ser dono

Se ownership fosse a única forma de acessar dados, você teria que transferir a propriedade toda vez que passasse algo pra uma função — e receber de volta depois. Inviável.

É aí que entra o borrowing: você empresta uma referência ao valor sem transferir o ownership.

TEXT
fn tamanho(s: &String) -> usize { // recebe uma referência, não o valor    s.len()}let minha_string = String::from("blueprint");let tam = tamanho(&minha_string); // passa a referênciaprintln!("{} tem {} caracteres", minha_string, tam);// ✅ minha_string ainda é válida — ownership não foi transferida

Referências mutáveis — e a regra mais importante do borrowing

Você pode emprestar mutabilidade também — mas com uma restrição crucial:

TEXT
let mut s = String::from("blueprint");let r1 = &mut s;let r2 = &mut s; // ❌ erro: não pode ter duas referências mutáveis ao mesmo tempo
TEXT
let mut s = String::from("blueprint");{    let r1 = &mut s;    r1.push_str(" blog");} // r1 sai de escopo aquilet r2 = &mut s; // ✅ agora pode — r1 já não existe

Essa regra elimina data races em tempo de compilação. Em Go ou C, dois threads podendo escrever no mesmo dado ao mesmo tempo é uma bomba-relógio. Em Rust, o compilador simplesmente não deixa isso acontecer.

💡

A regra completa do borrowing: você pode ter qualquer número de referências imutáveis ou exatamente uma referência mutável — nunca os dois ao mesmo tempo. Isso é suficiente pra eliminar toda uma categoria de bugs de concorrência.

Lifetimes: quando o compilador precisa de ajuda

O compilador do Rust consegue inferir a maioria das situações de ownership e borrowing automaticamente. Mas existe um caso onde ele precisa de uma dica explícita: quando uma função retorna uma referência, e o compilador precisa saber de qual dos parâmetros ela vem.

TEXT
// Sem lifetime — o compilador não sabe de onde vem a referência retornadafn maior(x: &str, y: &str) -> &str { // ❌ erro de compilação    if x.len() > y.len() { x } else { y }}
TEXT
// Com lifetime — o compilador sabe que o retorno vive tanto quanto x e yfn maior<'a>(x: &'a str, y: &'a str) -> &'a str { // ✅    if x.len() > y.len() { x } else { y }}

O 'a é uma anotação de lifetime. Ela não cria nada — só diz ao compilador: "a referência retornada vive pelo mesmo tempo que os dois parâmetros." Com essa informação, ele consegue verificar que você nunca vai retornar uma referência pra algo que já foi liberado.

⚠️

Lifetimes são o ponto de maior atrito em Rust. A boa notícia: o compilador precisou de anotações explícitas em casos bem mais simples antigamente. Versões modernas do Rust inferem lifetimes na maioria dos casos com as lifetime elision rules — você só precisa anotar quando a situação é genuinamente ambígua.

Comparando na prática: o mesmo bug em três linguagens

Use-after-free é uma das vulnerabilidades mais comuns e perigosas. Veja como cada linguagem lida com ela:

TEXT
/* C — compila, executa, comportamento indefinido */char *s = malloc(10);free(s);printf("%s", s); // acessa memória liberada — undefined behavior
TEXT
// Go — GC previne liberação prematura, mas com custo em runtime// O GC garante que s não será liberada enquanto ainda houver referênciass := "blueprint"fmt.Println(s) // sempre seguro, mas o GC adiciona overhead
TEXT
// Rust — erro em tempo de compilação, zero custo em runtimelet s = String::from("blueprint");drop(s); // libera explicitamenteprintln!("{}", s); // ❌ erro de compilação — o compilador recusa// esse código nunca chega em produção

Essa é a diferença fundamental: C descobre o problema em produção (quando já causou dano). Go previne em runtime com GC (mas paga o custo de latência). Rust previne em compile time — sem nenhum custo em runtime.

O que o compilador garante pra você
  • 1Ownership — cada valor tem um dono. Quando o dono sai de escopo, a memória é liberada automaticamente.
  • 2Move semantics — transferir um valor invalida a variável original. Double-free é impossível.
  • 3Borrowing — referenciar sem transferir. Imutável: quantas quiser. Mutável: só uma por vez.
  • 4Sem data race — duas referências mutáveis simultâneas não compilam. Concorrência segura por design.
  • 5Lifetimes — o compilador verifica que nenhuma referência sobrevive ao valor que ela aponta. Dangling pointers são impossíveis.
  • 6Zero custo em runtime — tudo isso é verificado em compilação. Em produção, o binário é tão rápido quanto C.

Continue explorando
Quer mais conteúdo assim?

Veja outros artigos na mesma linha e mantenha o ritmo.

Ver mais artigos
#Rust#Ownership#Go#Lifetimes

Arsenal do dev de elite.

Microfrontends com Angular e Nx: o que ninguém conta
Programação & Dev

Microfrontends com Angular e Nx: o que ninguém conta

Todo tutorial ensina a configurar microfrontends em minutos, mas poucos revelam o caos arquitetural que surge após meses de deploy em produção.

Genildo Souza · 28 de jul. · 16 min
Next.js 16 PPR: Elimine o tradeoff entre estático e dinâmico e alcance Edge TTFB com dados atualizados
Programação & Dev

Next.js 16 PPR: Elimine o tradeoff entre estático e dinâmico e alcance Edge TTFB com dados atualizados

O Partial Prerendering no Next.js 16 resolve o clássico tradeoff de renderização, entregando velocidade estática com dados dinâmicos em uma resposta.

Genildo Souza · 18 de jul. · 15 min
Pare de arriscar seu frontend: a arquitetura definitiva do Angular 22
Programação & Dev

Pare de arriscar seu frontend: a arquitetura definitiva do Angular 22

O Angular 22 chegou. Descubra como as mudanças arquiteturais e os novos primitivos de reatividade o tornam a escolha ideal para sistemas enterprise.

Genildo Souza · 11 de jul. · 18 min
Neste artigo
  • O problema que cada linguagem resolve diferente
  • Ownership: cada valor tem um dono
  • Borrowing: usar sem ser dono
  • Referências mutáveis — e a regra mais importante do borrowing
  • Lifetimes: quando o compilador precisa de ajuda
  • Comparando na prática: o mesmo bug em três linguagens