Rust 1.86 e 1.87: Trait Upcasting, Pipes e Novidades — 2026

Conheça as novidades do Rust 1.86 e 1.87: trait upcasting, get_disjoint_mut, io::pipe, intrínsecos seguros e muito mais com exemplos práticos.

Introdução

As versões 1.86 e 1.87 do Rust trouxeram recursos que mudam a forma como escrevemos código no dia a dia. Desde o esperado trait upcasting — que simplifica drasticamente o trabalho com trait objects — até pipes anônimos na stdlib e a possibilidade de chamar intrínsecos de arquitetura em código seguro, essas releases consolidam a missão do Rust: oferecer poder sem sacrificar segurança.

Neste artigo, vamos explorar cada recurso com exemplos de código prontos para você testar. Se você ainda não atualizou, basta rodar:

rustup update stable

Se quiser entender como instalar o Rust do zero, confira nosso guia de instalação.


Rust 1.86: Os Destaques

Trait Upcasting

O recurso mais aguardado do Rust 1.86 é, sem dúvida, o trait upcasting. Antes desta versão, converter uma referência &dyn Trait para &dyn Supertrait exigia gambiarras manuais — métodos auxiliares como fn as_supertrait(&self) -> &dyn Supertrait. Agora, a conversão é automática:

trait Animal {
    fn nome(&self) -> &str;
}

trait Cachorro: Animal {
    fn latir(&self) -> String;
}

struct Labrador {
    nome: String,
}

impl Animal for Labrador {
    fn nome(&self) -> &str {
        &self.nome
    }
}

impl Cachorro for Labrador {
    fn latir(&self) -> String {
        format!("{} diz: Au au!", self.nome())
    }
}

fn imprimir_animal(animal: &dyn Animal) {
    println!("Animal: {}", animal.nome());
}

fn main() {
    let rex: Box<dyn Cachorro> = Box::new(Labrador {
        nome: "Rex".to_string(),
    });

    // Antes do 1.86: erro de compilação!
    // Agora: conversão automática de &dyn Cachorro → &dyn Animal
    imprimir_animal(&*rex);

    // Também funciona com Arc e Rc
    let rex_arc: std::sync::Arc<dyn Cachorro> = std::sync::Arc::new(Labrador {
        nome: "Rex".to_string(),
    });
    let animal_arc: std::sync::Arc<dyn Animal> = rex_arc;
    println!("Via Arc: {}", animal_arc.nome());
}

Se você trabalha com trait objects e generics, esse recurso elimina uma enorme fonte de boilerplate. Combinado com smart pointers como Arc e Rc, o trait upcasting torna padrões de polimorfismo dinâmico muito mais ergonômicos.

Para um guia completo sobre traits, confira nosso artigo sobre traits em Rust.

get_disjoint_mut: Múltiplas Referências Mutáveis Seguras

Um dos problemas clássicos do Rust é acessar dois elementos mutáveis de um slice ou HashMap ao mesmo tempo. O compilador impede porque não consegue provar em tempo de compilação que os índices são diferentes. O novo método get_disjoint_mut resolve isso:

fn main() {
    let mut valores = vec![10, 20, 30, 40, 50];

    // Antes: split_at_mut ou unsafe
    // Agora: get_disjoint_mut!
    if let Ok([a, c]) = valores.get_disjoint_mut([0, 2]) {
        *a += 100;
        *c += 200;
        println!("a={}, c={}", a, c); // a=110, c=230
    }

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

Isso funciona também com HashMap:

use std::collections::HashMap;

fn main() {
    let mut mapa = HashMap::new();
    mapa.insert("x", 1);
    mapa.insert("y", 2);
    mapa.insert("z", 3);

    if let Ok([vx, vz]) = mapa.get_disjoint_mut(["x", "z"]) {
        *vx *= 10;
        *vz *= 10;
    }

    println!("{:?}", mapa); // {"x": 10, "y": 2, "z": 30}
}

Se você usa Vec ou HashMap no dia a dia, esse método elimina a necessidade de unsafe ou split_at_mut para o caso mais comum de acesso simultâneo.

#[target_feature] em Funções Seguras

Antes do 1.86, usar #[target_feature] exigia que a função fosse unsafe. Agora, funções seguras podem ser marcadas com features de CPU específicas:

#[target_feature(enable = "avx2")]
fn soma_vetorial_avx2(a: &[f32; 8], b: &[f32; 8]) -> [f32; 8] {
    let mut resultado = [0.0f32; 8];
    for i in 0..8 {
        resultado[i] = a[i] + b[i];
    }
    resultado
}

fn main() {
    if std::is_x86_feature_detected!("avx2") {
        let a = [1.0; 8];
        let b = [2.0; 8];
        let resultado = soma_vetorial_avx2(&a, &b);
        println!("Resultado: {:?}", resultado);
    } else {
        println!("AVX2 não disponível neste processador");
    }
}

Para quem trabalha com otimização de performance, isso reduz a quantidade de unsafe no código sem perder controle sobre instruções SIMD.

Asserções de Ponteiro Nulo em Debug

O compilador agora insere verificações automáticas em modo debug para detectar desreferência de ponteiros nulos antes de qualquer leitura ou escrita de tamanho diferente de zero. Se você usa ponteiros e unsafe, isso ajuda a pegar bugs mais cedo durante o desenvolvimento.


Rust 1.87: Os Destaques

io::pipe — Pipes Anônimos na Stdlib

Finalmente temos pipes nativos na biblioteca padrão! O std::io::pipe() cria um par leitor/escritor que funciona tanto no Unix quanto no Windows:

use std::io::{self, Read, Write};
use std::thread;

fn main() -> io::Result<()> {
    let (mut reader, mut writer) = io::pipe()?;

    let handle = thread::spawn(move || {
        writer.write_all(b"Olá do Rust 1.87!").unwrap();
        writer.write_all(b" Pipes nativos!").unwrap();
        // writer é dropado aqui, sinalizando EOF
    });

    let mut buffer = String::new();
    reader.read_to_string(&mut buffer)?;
    println!("Recebido: {}", buffer);

    handle.join().unwrap();
    Ok(())
}

Para quem trabalha com threads e canais de comunicação, io::pipe oferece uma alternativa baseada em I/O que se integra bem com processos filhos e redirects de stdin/stdout.

Intrínsecos de Arquitetura Seguros

A maioria dos intrínsecos em std::arch agora pode ser chamada sem unsafe quando as features de CPU apropriadas estão habilitadas. Isso é uma revolução para código SIMD:

#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse4.1")]
fn soma_inteiros_sse(a: &[i32; 4], b: &[i32; 4]) -> [i32; 4] {
    use std::arch::x86_64::*;

    // Antes: unsafe { _mm_add_epi32(...) }
    // Agora: chamada segura!
    let va = unsafe { _mm_loadu_si128(a.as_ptr() as *const _) };
    let vb = unsafe { _mm_loadu_si128(b.as_ptr() as *const _) };
    let resultado = unsafe { _mm_add_epi32(va, vb) };

    let mut out = [0i32; 4];
    unsafe { _mm_storeu_si128(out.as_mut_ptr() as *mut _, resultado) };
    out
}

Vec::extract_if — Filtrar e Remover Elementos

O método extract_if permite filtrar e remover elementos de um Vec em uma única passagem, retornando os elementos removidos como iterador:

fn main() {
    let mut numeros = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    // Extrai todos os pares (remove do vec e retorna como iterador)
    let pares: Vec<i32> = numeros.extract_if(.., |x| *x % 2 == 0).collect();

    println!("Pares removidos: {:?}", pares);    // [2, 4, 6, 8, 10]
    println!("Ímpares restantes: {:?}", numeros); // [1, 3, 5, 7, 9]
}

Antes, você precisava de retain (que descarta os removidos) ou loops manuais. Agora, com extract_if, você mantém ambos os conjuntos. Muito útil para filtrar coleções em processamento de dados.

String::extend_from_within

Novo método para duplicar partes de uma String sem alocar strings intermediárias:

fn main() {
    let mut texto = String::from("Rust");
    texto.extend_from_within(..);
    println!("{}", texto); // "RustRust"

    let mut saudacao = String::from("Olá, mundo!");
    saudacao.extend_from_within(0..4);
    println!("{}", saudacao); // "Olá, mundo!Olá,"
}

Qual Versão Usar?

Se você está começando agora, use sempre a versão estável mais recente. Nosso guia Como Aprender Rust em 2026 tem o caminho completo. Para atualizar:

rustup update stable
rustc --version

Resumo das Novidades

RecursoVersãoImpacto
Trait upcasting1.86Polimorfismo dinâmico mais ergonômico
get_disjoint_mut1.86Acesso mutável simultâneo seguro
#[target_feature] safe1.86Menos unsafe em código SIMD
Null pointer assertions1.86Debug mais seguro
io::pipe1.87Pipes nativos na stdlib
Safe arch intrinsics1.87SIMD sem unsafe desnecessário
Vec::extract_if1.87Filtrar + remover em uma passagem
String::extend_from_within1.87Duplicação eficiente de substrings

Leia Também

Se você vem de outra linguagem, confira também como Rust se compara: Go, Python, Kotlin e Zig são linguagens que frequentemente aparecem em comparações com Rust.