Rust

O Futuro do Rust — Async Traits, GATs, Especialização e o Roadmap da Linguagem Já leu

16 min de leitura

O Futuro do Rust — Async Traits, GATs, Especialização e o Roadmap da Linguagem
Rust — Artigo #50 O Futuro do Rust — Async Traits, GATs, Especialização e o Roadmap da Linguagem Por Prof. Dr. Marcelo Fontes | Série: Dominando Rust em 1 Ano R

Rust — Artigo #50

O Futuro do Rust — Async Traits, GATs, Especialização e o Roadmap da Linguagem

Por Prof. Dr. Marcelo Fontes | Série: Dominando Rust em 1 Ano


Rust é uma linguagem viva. Cada edição — 2015, 2018, 2021 — consolidou avanços significativos. O pipeline de desenvolvimento é transparente: RFCs públicos, tracking issues abertas, implementações progressivas em nightly antes da estabilização em stable. Você pode acompanhar em tempo real o que está sendo construído.

Este artigo examina as fronteiras atuais da linguagem: o que acabou de ser estabilizado, o que está em nightly aguardando estabilização, e o que está sendo debatido para o futuro. Entender o roadmap não é só curiosidade — é saber onde investir energia de aprendizado e como desenhar sistemas que se beneficiarão das melhorias que vêm por aí.


O que chegou recentemente ao stable

Async fn em traits — estabilizado no Rust 1.75

// Antes do Rust 1.75 — async fn em traits era impossível
// sem workarounds ou crates como async-trait

// ANTES (workaround com async-trait):
// use async_trait::async_trait;
// #[async_trait]
// trait Repositorio {
//     async fn buscar(&self, id: u64) -> Option<Usuario>;
// }

// AGORA — nativo e sem overhead de Box<dyn Future>:
use std::future::Future;

trait Repositorio {
    async fn buscar(&self, id: u64) -> Option<Usuario>;
    async fn salvar(&mut self, usuario: &Usuario) -> Result<(), ErroDb>;
    async fn deletar(&mut self, id: u64) -> bool;
}

struct RepositorioPostgres {
    pool: Pool,
}

impl Repositorio for RepositorioPostgres {
    async fn buscar(&self, id: u64) -> Option<Usuario> {
        // Implementação real consultaria o banco
        let row = self.pool.query_one(
            "SELECT * FROM usuarios WHERE id = $1",
            &[&(id as i64)],
        ).await.ok()?;

        Some(Usuario {
            id,
            nome: row.get("nome"),
            email: row.get("email"),
        })
    }

    async fn salvar(&mut self, usuario: &Usuario) -> Result<(), ErroDb> {
        self.pool.execute(
            "INSERT INTO usuarios (id, nome, email) VALUES ($1, $2, $3)
             ON CONFLICT (id) DO UPDATE SET nome = $2, email = $3",
            &[&(usuario.id as i64), &usuario.nome, &usuario.email],
        ).await.map(|_| ()).map_err(ErroDb::Postgres)
    }

    async fn deletar(&mut self, id: u64) -> bool {
        self.pool.execute(
            "DELETE FROM usuarios WHERE id = $1",
            &[&(id as i64)],
        ).await.map(|n| n > 0).unwrap_or(false)
    }
}

// A limitação ainda existente: async fn em traits não é
// object-safe por padrão. Para trait objects, use RPIT:
trait ServicoNotificacao {
    fn notificar(
        &self,
        mensagem: &str,
    ) -> impl Future<Output = Result<(), ErroNotif>> + Send;
}

// Stubs
struct Usuario { id: u64, nome: String, email: String }
struct Pool;
impl Pool {
    async fn query_one(&self, _: &str, _: &[&dyn std::fmt::Debug])
        -> Result<Row, String> { Ok(Row) }
    async fn execute(&self, _: &str, _: &[&dyn std::fmt::Debug])
        -> Result<u64, PgError> { Ok(1) }
}
struct Row;
impl Row { fn get(&self, _: &str) -> String { String::new() } }
struct PgError;
#[derive(Debug)] enum ErroDb { Postgres(PgError) }
#[derive(Debug)] struct ErroNotif;

Return Position Impl Trait (RPIT) em traits — Rust 1.75

// Permite retornar tipos opacos em traits

trait Processador {
    // Retorna um iterador sem nomear o tipo concreto
    fn processar<'a>(
        &'a self,
        dados: &'a [u8],
    ) -> impl Iterator<Item = u8> + 'a;

    // Retorna um Future opaco
    fn processar_async(
        &self,
        dados: Vec<u8>,
    ) -> impl Future<Output = Vec<u8>> + Send + '_;
}

struct ProcessadorBase64;

impl Processador for ProcessadorBase64 {
    fn processar<'a>(
        &'a self,
        dados: &'a [u8],
    ) -> impl Iterator<Item = u8> + 'a {
        // O tipo do iterador é inferido — não precisa ser nomeado
        dados.iter()
            .map(|&b| if b.is_ascii_alphabetic() {
                b.to_ascii_uppercase()
            } else {
                b
            })
    }

    fn processar_async(
        &self,
        dados: Vec<u8>,
    ) -> impl Future<Output = Vec<u8>> + Send + '_ {
        async move {
            tokio::time::sleep(std::time::Duration::from_millis(1)).await;
            dados.iter().map(|&b| b.wrapping_add(1)).collect()
        }
    }
}

GATs — Generic Associated Types — Rust 1.65

// GATs permitem tipos associados que são genéricos
// sobre lifetimes ou outros parâmetros de tipo

// Sem GATs — impossível expressar este padrão:
trait ColecaoSemGat {
    type Item;
    // Como retornar uma referência com lifetime ligado ao self?
    // fn iter(&self) -> impl Iterator<Item = &Self::Item>; // não funcionava
}

// COM GATs — expressivo e preciso:
trait Colecao {
    type Item;

    // GAT: o tipo de retorno é genérico sobre o lifetime 'a
    type Iter<'a>: Iterator<Item = &'a Self::Item>
    where
        Self: 'a;

    fn iter<'a>(&'a self) -> Self::Iter<'a>;
}

struct VecColecao<T>(Vec<T>);

impl<T> Colecao for VecColecao<T> {
    type Item = T;
    type Iter<'a> = std::slice::Iter<'a, T>
    where
        T: 'a;

    fn iter<'a>(&'a self) -> Self::Iter<'a> {
        self.0.iter()
    }
}

// GATs para streaming — padrão muito útil:
trait StreamingIterator {
    type Item<'a> where Self: 'a;
    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}

struct LinhasDoCsv {
    buffer: String,
    linhas: Vec<String>,
    posicao: usize,
}

impl StreamingIterator for LinhasDoCsv {
    // O item empresta do iterador, não do caller
    type Item<'a> = &'a str where Self: 'a;

    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
        if self.posicao < self.linhas.len() {
            let linha = &self.linhas[self.posicao];
            self.posicao += 1;
            Some(linha.as_str())
        } else {
            None
        }
    }
}

Em nightly — caminho para estabilização

Especialização (Specialization)

// #![feature(specialization)] — nightly, há anos em debate
// Permite implementações mais específicas sobrescrever as gerais

#![feature(min_specialization)]

// Exemplo: implementação padrão e especializada
trait Serializar {
    fn serializar(&self) -> String;
}

// Implementação geral para qualquer Debug
impl<T: std::fmt::Debug> Serializar for T {
    default fn serializar(&self) -> String {
        format!("{:?}", self)
    }
}

// Especialização para String — mais eficiente
impl Serializar for String {
    fn serializar(&self) -> String {
        format!(""{}"", self.replace('"', "\""))
    }
}

// Especialização para números — sem aspas
impl Serializar for i64 {
    fn serializar(&self) -> String {
        self.to_string()
    }
}

// Uso real: a impl certa é chamada automaticamente
fn demo_especializacao() {
    let s = String::from("hello "world"");
    let n: i64 = 42;
    let v = vec![1, 2, 3];

    println!("{}", s.serializar()); // "hello "world""
    println!("{}", n.serializar()); // 42
    println!("{}", v.serializar()); // [1, 2, 3]
}

// Por que está demorando tanto para estabilizar?
// O problema da soundness com lifetimes:
//
// impl<T: Clone> Processar for T {
//     default fn processar(&self) -> String { ... }
// }
// impl Processar for &str {
//     fn processar(&self) -> String { ... }
// }
// Mas: impl<'a> Processar for &'a str pode ser mais geral
// que impl Processar for &'static str — o compilador pode
// escolher a impl errada em alguns casos com lifetimes.
// A solução (min_specialization) restringe os casos permitidos.

Async closures

// #![feature(async_closure)] — nightly, Rust 2024 Edition
// Closures que podem usar .await internamente

// ANTES — workaround verbose:
fn processar_itens_antes<T, F, Fut>(
    itens: Vec<T>,
    f: F,
) -> impl Future<Output = Vec<String>>
where
    F: Fn(T) -> Fut,
    Fut: Future<Output = String>,
{
    async move {
        let mut resultados = Vec::new();
        for item in itens {
            resultados.push(f(item).await);
        }
        resultados
    }
}

// COM async closures — muito mais natural:
async fn processar_itens<T: Send>(
    itens: Vec<T>,
    f: impl async Fn(T) -> String,
) -> Vec<String> {
    let mut resultados = Vec::new();
    for item in itens {
        resultados.push(f(item).await);
    }
    resultados
}

// Uso:
async fn exemplo_async_closure() {
    let nums = vec![1u32, 2, 3, 4, 5];

    let resultados = processar_itens(nums, async |n| {
        // Pode usar await diretamente na closure!
        tokio::time::sleep(std::time::Duration::from_millis(n as u64)).await;
        format!("resultado_{n}")
    }).await;

    println!("{:?}", resultados);
}

// Por que async closures são complexas de implementar?
// Uma closure captura por referência por padrão.
// Uma async closure retorna um Future que pode viver mais
// que a closure original. Reconciliar esses lifetimes
// com a semântica de captura requereu design cuidadoso.

Polonius — novo borrow checker

// O borrow checker atual (NLL) às vezes rejeita código correto.
// Polonius é uma reformulação baseada em Datalog que é
// mais precisa e aceita todos os programas que NLL aceita
// mais alguns programas corretos que NLL rejeita.

// Exemplo clássico que NLL rejeita mas Polonius aceita:
fn obter_ou_inserir<'a>(
    mapa: &'a mut std::collections::HashMap<String, String>,
    chave: &str,
) -> &'a str {
    // Com NLL, isso às vezes falha com erro de borrow
    // mesmo sendo correto — o borrow de `mapa` em `get`
    // parece conflitar com o borrow em `insert`

    if let Some(valor) = mapa.get(chave) {
        return valor; // emprestado de mapa
    }

    // NLL pensa que o borrow imutável de `get` ainda está ativo
    // Polonius entende que ele terminou no `return` acima
    mapa.insert(chave.to_string(), "padrão".to_string());
    mapa.get(chave).unwrap()
}

// Ativa Polonius em nightly:
// RUSTFLAGS="-Z polonius" cargo +nightly build

// Polonius também habilita análise mais precisa de lifetimes
// em closures capturando partes de structs:

struct Config {
    host: String,
    porta: u16,
    opcoes: std::collections::HashMap<String, String>,
}

fn processar_config(config: &mut Config) {
    let host = &config.host; // borrow de um campo

    // Com NLL, isso pode falhar porque `config` está emprestado
    // Com Polonius, o compilador entende que apenas `host`
    // (não `opcoes`) está emprestado
    config.opcoes.insert("chave".to_string(), host.clone());
}

Ergonomias de pattern matching

// Várias melhorias de ergonomia chegando/chegaram:

// 1. or-patterns — estabilizado no Rust 1.53
let x = Some(3);
match x {
    Some(1 | 2 | 3) => println!("pequeno"),
    Some(n) => println!("outro: {n}"),
    None => println!("nenhum"),
}

// 2. if let chains — estabilizado no Rust 1.64
fn processar(opt_a: Option<i32>, opt_b: Option<i32>) {
    if let Some(a) = opt_a
        && let Some(b) = opt_b
        && a + b > 10
    {
        println!("Soma {}: maior que 10", a + b);
    }
}

// 3. let-else — estabilizado no Rust 1.65
fn parsear_porta(s: &str) -> Option<u16> {
    let Ok(n) = s.parse::<u16>() else {
        return None;
    };
    // n está disponível aqui como u16
    Some(n)
}

// 4. Binding modes melhorados — em discussão
// Atualmente:
fn exemplo_binding_atual(opt: &Option<String>) {
    if let Some(s) = opt {
        // s é &String — binding mode automático
        println!("{s}");
    }
}

// 5. Deref patterns — em RFC/nightly
// Permite fazer match em Box<T>, Rc<T>, etc. diretamente:
// match boxed_value {
//     box 42 => println!("quarenta e dois"),
//     box n  => println!("outro: {n}"),
// }

O que está sendo debatido para o futuro

Efeitos e capacidades (Effects/Capabilities)

// Uma das discussões mais importantes do momento.
// Rust tem vários "modificadores" que se combinam de forma
// inconsistente: async, unsafe, const, ?Trait...

// A visão: um sistema unificado de "efeitos" onde:

// Atual (inconsistente):
async fn operacao_async() -> u32 { 42 }
unsafe fn operacao_unsafe() -> u32 { 42 }
const fn operacao_const() -> u32 { 42 }

// Impossível hoje (função genérica sobre ser async ou não):
// fn pode_ser_async_ou_nao?() -> u32 { ... }

// Com effects (visão futura):
// fn generico<effect E>() -> u32
// where
//     E: maybeasync + maybeunsafe
// { ... }

// Por que isso importa?
// Imagine uma crate de parsing que quer ser:
// - síncrona para uso simples
// - assíncrona para I/O
// - const para uso em tempo de compilação
// Hoje você precisaria de três implementações separadas.
// Com effects, uma só implementação serviria a todos.

// Isso está em fase de RFC/discussão — anos até estabilizar.
// Mas molda muitas decisões de design tomadas hoje.

const generics avançados

// O que já funciona (Rust 1.51+):
fn array_de_zeros<const N: usize>() -> [f64; N] {
    [0.0; N]
}

struct MatrizFixa<T, const LINHAS: usize, const COLS: usize> {
    dados: [[T; COLS]; LINHAS],
}

impl<T: Copy + Default, const L: usize, const C: usize>
    MatrizFixa<T, L, C>
{
    fn novo() -> Self {
        MatrizFixa {
            dados: [[T::default(); C]; L],
        }
    }

    fn get(&self, linha: usize, col: usize) -> Option<&T> {
        self.dados.get(linha)?.get(col)
    }
}

// O que está chegando — const expressions mais ricas:
// #![feature(generic_const_exprs)] — nightly, instável

// Permite expressões aritméticas em const generics:
// fn concatenar_arrays<const N: usize, const M: usize>(
//     a: [u8; N],
//     b: [u8; M],
// ) -> [u8; N + M] {  // N + M como const generic!
//     ...
// }

// Permite const em bounds:
// fn requer_pelo_menos_dois<T, const N: usize>(arr: [T; N])
// where
//     [(); N - 2]:,  // garante N >= 2 em compile time
// {
//     ...
// }

// Por que é difícil?
// O type checker precisa provar propriedades aritméticas.
// 2 + 2 == 4 é trivial. N + M == M + N requer comutatividade.
// Casos com variáveis são indecidíveis em geral.

Rust 2024 Edition

// Edições do Rust não são versões — são "lentes" que
// permitem mudanças de sintaxe sem quebrar código antigo.
// Todo código Rust, de toda edição, compila junto.

// Mudanças confirmadas na Rust 2024 Edition:

// 1. RPIT lifetime capture mais preciso
// Rust 2021:
fn iter_2021(dados: &[u32]) -> impl Iterator<Item = u32> {
    // Implicitamente captura o lifetime de `dados`
    dados.iter().copied()
}
// Rust 2024:
fn iter_2024(dados: &[u32]) -> impl Iterator<Item = u32> + use<'_> {
    // Explícito sobre quais lifetimes são capturados
    dados.iter().copied()
}

// 2. gen blocks (geradores/coroutines) — em discussão para 2024
// Permite escrever iteradores de forma imperativa:
// fn fibonacci() -> impl Iterator<Item = u64> {
//     gen {
//         let (mut a, mut b) = (0u64, 1u64);
//         loop {
//             yield a;
//             (a, b) = (b, a + b);
//         }
//     }
// }

// 3. async gen — iteradores assíncronos com sintaxe natural
// async fn stream_de_eventos() -> impl Stream<Item = Evento> {
//     async gen {
//         loop {
//             let evento = aguardar_proximo_evento().await;
//             yield evento;
//         }
//     }
// }

// 4. Mudanças em match ergonomics
// Tornar o comportamento mais consistente e previsível

// 5. Migração mais suave de unsafe
// Novos avisos para padrões unsafe que serão erros no futuro

Tendências do ecossistema

Async Rust em maturação

// O ecossistema async está convergindo após anos de fragmentação

// tokio — runtime dominante para servidores
// smol/async-std — alternativas mais leves
// embassy — async para embedded (sem OS)

// A padronização que está chegando:

// 1. AsyncIterator (antes Stream) — na stdlib
// use std::async_iter::AsyncIterator;
// Permitirá: for await item in stream { ... }

// 2. AsyncRead/AsyncWrite na stdlib
// Hoje: tokio::io::{AsyncRead, AsyncWrite}
//       futures::io::{AsyncRead, AsyncWrite}
// São incompatíveis! Stdlib resolveria isso.

// 3. AsyncDrop — complexo, em discussão
// Permite .await em destructors — necessário para
// conexões de banco que precisam enviar FIN assíncrono

// Código atual que vai melhorar:
use tokio::io::{AsyncReadExt, AsyncWriteExt};

async fn copiar_com_buffer(
    mut leitor: impl tokio::io::AsyncRead + Unpin,
    mut escritor: impl tokio::io::AsyncWrite + Unpin,
) -> std::io::Result<u64> {
    let mut buffer = vec![0u8; 64 * 1024];
    let mut total = 0u64;

    loop {
        let n = leitor.read(&mut buffer).await?;
        if n == 0 { break; }
        escritor.write_all(&buffer[..n]).await?;
        total += n as u64;
    }

    Ok(total)
}

Rust no kernel Linux

// Desde o kernel 6.1 (dezembro 2022), Rust é suportado
// oficialmente como segunda linguagem no kernel Linux.

// Módulos de kernel em Rust — exemplo simplificado:
// (código real usa infraestrutura do kernel)

// use kernel::prelude::*;
// use kernel::{Module, ThisModule, file};
//
// module! {
//     type: MeuModulo,
//     name: "meu_modulo",
//     author: "Desenvolvedor",
//     description: "Módulo de exemplo em Rust",
//     license: "GPL",
// }
//
// struct MeuModulo;
//
// impl kernel::Module for MeuModulo {
//     fn init(_name: &'static CStr, _module: &'static ThisModule)
//         -> Result<Self>
//     {
//         pr_info!("Módulo Rust inicializado
");
//         Ok(MeuModulo)
//     }
// }
//
// impl Drop for MeuModulo {
//     fn drop(&mut self) {
//         pr_info!("Módulo Rust descarregado
");
//     }
// }

// Por que isso importa?
// O kernel Linux roda em todo servidor, smartphone Android,
// e dispositivo IoT. Rust no kernel significa:
// - Drivers novos podem ser escritos em Rust
// - Menor superfície de CVEs por memory safety
// - Pressão para Rust suportar ambientes no-std avançados
// - Validação definitiva de Rust como linguagem de sistemas

Rastreando o progresso

# Fontes para acompanhar o desenvolvimento do Rust:

# 1. Blog oficial — anúncios de releases
# https://blog.rust-lang.org

# 2. Inside Rust — posts do time de desenvolvimento
# https://blog.rust-lang.org/inside-rust/

# 3. This Week in Rust — curadoria semanal
# https://this-week-in-rust.org

# 4. Tracking issues — o que está em desenvolvimento
# https://github.com/rust-lang/rust/labels/C-tracking-issue

# 5. Unstable Book — features em nightly documentadas
# https://doc.rust-lang.org/unstable-book/

# 6. Rust Roadmap
# https://github.com/rust-lang/rust/milestone/

# Como experimentar features de nightly com segurança:

# rust-toolchain.toml — fixa a toolchain por projeto
cat > rust-toolchain.toml << 'EOF'
[toolchain]
channel = "nightly-2024-01-15"  # data específica — reprodutível
components = ["rustfmt", "clippy", "miri"]
targets = ["wasm32-unknown-unknown"]
EOF

# Ativa feature apenas para um módulo
// src/experimental.rs
#![cfg_attr(feature = "nightly", feature(async_closure))]
#![cfg_attr(feature = "nightly", feature(gen_blocks))]

// Cargo.toml
// [features]
// nightly = []

Um olhar panorâmico: o que Rust provou

// Ao longo desta série de 50 artigos, construímos sistemas em:
// - Web (APIs, WebSockets, WebAssembly)
// - Sistemas distribuídos (consenso, mensageria)
// - Embedded (sem SO, bare metal)
// - Compiladores e interpretadores
// - Blockchain e criptografia
// - Machine learning (inferência, treinamento)
// - GameDev (ECS, Bevy)
// - CLIs profissionais
// - Sistemas operacionais (conceitos)

// O que Rust provou ao longo desses domínios:

// 1. SEGURANÇA SEM CUSTO DE RUNTIME
// Sem GC, sem overhead, sem pausas.
// Performance de C com segurança de linguagens modernas.

// 2. EXPRESSIVIDADE DE ALTO NÍVEL
// Iteradores, closures, traits, generics —
// a abstração zero-cost não é só marketing.

// 3. CONFIABILIDADE EM ESCALA
// "If it compiles, it often works" não é mito.
// O compilador pega classes de bugs que outros sistemas
// só encontram em produção.

// 4. ECOSSISTEMA MADURO
// Cargo é o melhor gerenciador de pacotes de qualquer linguagem.
// crates.io tem soluções de qualidade para quase todo domínio.

// 5. COMUNIDADE EXCEPCIONAL
// Rust foi eleita a linguagem "mais amada" por 8 anos
// consecutivos no Stack Overflow Developer Survey (2016-2023).
// Isso não é coincidência — é o resultado de uma cultura
// que valoriza tanto correctness quanto experiência do desenvolvedor.

// O que Rust ainda está construindo:
// - Async mais ergonômico (closures, iteradores, drop)
// - Especialização estável
// - Effects system para composição de capacidades
// - Melhor suporte a reflexão (limitada por design)
// - Compilação incremental ainda mais rápida
// - Diagnósticos de erro ainda mais claros

Fontes e leituras recomendadas

  • Rust Blog — anúncios oficiais — https://blog.rust-lang.org
  • Inside Rust Blog — desenvolvimento interno — https://blog.rust-lang.org/inside-rust/
  • Rust Unstable Book — features em nightly — https://doc.rust-lang.org/unstable-book/
  • RFC Repository — propostas em discussão — https://github.com/rust-lang/rfcs
  • Tracking Issues — o que está sendo implementado — https://github.com/rust-lang/rust/labels/C-tracking-issue
  • "Polonius: The Next-Generation Borrow Checker" — https://blog.rust-lang.org/2022/08/05/nll-by-default.html
  • "Async Rust in 2024" — https://without.boats/blog/
  • Rust Zulip — conversa em tempo real com o time — https://rust-lang.zulipchat.com
  • "The Rust Performance Book" — https://nnethercote.github.io/perf-book/

Artigo #50 de 52 | Série: Dominando Rust em 1 Ano Próximo → Artigo #51: Projetos Integradores — Construindo sistemas completos do zero


Comentários

Mais em Rust

Programação de Redes — TCP, UDP e Sockets
Programação de Redes — TCP, UDP e Sockets

Toda a infraestrutura digital moderna roda sobre protocolos de rede. Quando v...

Contribuindo com o Ecossistema Rust — Open Source, RFCs e a Comunidade
Contribuindo com o Ecossistema Rust — Open Source, RFCs e a Comunidade

Rust — Artigo #49 Contribuindo com o Ecossistema Rust — Open Source, RFCs e a...

Macros Procedurais — Criando Derive Macros e Atributos Customizados
Macros Procedurais — Criando Derive Macros e Atributos Customizados

No Artigo #21 exploramos macros declarativas com macro_rules! — padrões que t...