0Pricing
Learn Rust Coding · Aula

Movendo dados para threads

Use closures move corretamente.

Movendo dados para threads é uma aula grátis de Learn Rust Coding no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Learn Rust Coding, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Learn Rust Coding inclui 4 aulas no total.

Closures capturam o ambiente

Uma closure passada para thread::spawn pode usar variáveis do scope ao redor. Por padrão, o Rust faz um empréstimo delas.

Porém, uma thread criada pode sobreviver à função que a criou, então um empréstimo comum não é seguro. O Rust rejeita isso em tempo de compilação.

O problema dos empréstimos

Se uma thread faz um empréstimo de uma variável local, o compilador não consegue provar que a variável viverá tempo suficiente. A thread poderia continuar executando depois que a variável fosse descartada.

O código abaixo não compila, porque a closure apenas faz um empréstimo de data.

use std::thread;

fn main() {
    let data = vec![1, 2, 3];
    // ERROR: closure may outlive `data`
    let h = thread::spawn(|| {
        println!("{:?}", data);
    });
    h.join().unwrap();
}

A palavra-chave move

Adicionar move antes da closure faz com que ela assuma a propriedade das variáveis capturadas. Elas são movidas para dentro da thread.

Agora a thread é proprietária dos dados, então eles permanecem válidos durante o lifetime da thread.

use std::thread;

fn main() {
    let data = vec![1, 2, 3];
    let h = thread::spawn(move || {
        println!("{:?}", data);
    });
    h.join().unwrap();
}

A propriedade é transferida

Depois que um valor é movido para uma thread, o scope original não pode mais usá-lo. A propriedade foi transferida.

Tentar usar data em main depois da movimentação causaria um erro de compilação. A thread agora é a única proprietária.

use std::thread;

fn main() {
    let data = vec![1, 2, 3];
    let h = thread::spawn(move || println!("{:?}", data));
    // println!("{:?}", data); // ERROR: value moved
    h.join().unwrap();
}

Movendo tipos Copy

Tipos que implementam Copy, como inteiros, são copiados em vez de movidos. A closure recebe sua própria cópia.

Assim, depois que uma closure move captura um número, você ainda pode usar o original em main.

use std::thread;

fn main() {
    let n = 42;
    let h = thread::spawn(move || {
        println!("thread sees {}", n);
    });
    println!("main still sees {}", n);
    h.join().unwrap();
}

Send: transferência segura

Um tipo só pode ser movido para outra thread se implementar a trait Send. Send significa que é seguro transferir a propriedade entre threads.

A maioria dos tipos é Send automaticamente. Alguns, como Rc, não são, e o compilador rejeitará a movimentação deles.

Rc não é Send

Rc é um contador de referências para uma única thread. Seu contador não é protegido contra atualizações concorrentes, por isso ele não é Send.

Tentar mover um Rc para uma thread não compila. Na próxima lição, você usará Arc no lugar dele.

use std::rc::Rc;
use std::thread;

fn main() {
    let r = Rc::new(5);
    // ERROR: `Rc<i32>` cannot be sent between threads safely
    let h = thread::spawn(move || println!("{}", r));
    h.join().unwrap();
}

Movendo vários valores

Uma única closure move pode capturar várias variáveis de uma vez. Todas elas são movidas para a thread.

Isso é útil quando um worker precisa de algum input e de um label.

use std::thread;

fn main() {
    let label = String::from("sum");
    let nums = vec![1, 2, 3, 4];
    let h = thread::spawn(move || {
        let total: i32 = nums.iter().sum();
        println!("{} = {}", label, total);
    });
    h.join().unwrap();
}

Clonando antes de mover

Se tanto a thread quanto a função principal precisam de um valor, faça um clone dele primeiro. Dê um clone à thread e keep o outro.

Clonar copia os dados, então cada lado é proprietário de um valor independente.

use std::thread;

fn main() {
    let original = String::from("hello");
    let for_thread = original.clone();
    let h = thread::spawn(move || println!("thread: {}", for_thread));
    println!("main: {}", original);
    h.join().unwrap();
}

Retornando os dados movidos

Uma thread que é proprietária de dados movidos pode retorná-los, devolvendo a propriedade à thread pai por meio de join.

Esse padrão move os dados para dentro, processa-os e depois move o resultado para fora.

use std::thread;

fn main() {
    let mut v = vec![3, 1, 2];
    let h = thread::spawn(move || {
        v.sort();
        v
    });
    let sorted = h.join().unwrap();
    println!("{:?}", sorted);
}

Por que move é necessário

Sem move, o verificador de empréstimos presume que a closure faz um empréstimo. Como as threads criadas não têm um lifetime fixo vinculado ao chamador, os empréstimos não são seguros.

A palavra-chave move transforma empréstimos em transferências de propriedade, satisfazendo o requisito 'static de spawn.

Verificação rápida

Teste sua compreensão sobre como mover dados para as threads.

Recapitulação

Você aprendeu que as closures de threads devem ser proprietárias dos dados que usam, o que é obtido com a palavra-chave move.

Mover transfere a propriedade, enquanto os tipos Copy são copiados. A trait Send indica o que é seguro transferir, e Rc não é Send.

A seguir, você compartilhará dados entre threads usando Arc e Mutex.

Perguntas Frequentes

A aula “Movendo dados para threads” é grátis?

Sim — o texto completo de “Movendo dados para threads” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Learn Rust Coding, atualize para CoddyKit PRO. O curso de Learn Rust Coding inclui 4 aulas no total.

O que vou aprender em “Movendo dados para threads”?

Use closures move corretamente. Você pratica Learn Rust Coding com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Learn Rust Coding?

Nenhuma experiência prévia é necessária. Learn Rust Coding no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Movendo dados para threads”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Learn Rust Coding?

Sim. Cada aula de Learn Rust Coding inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Criando threads
  2. Movendo dados para threads
  3. Compartilhando com Arc e Mutex
  4. Unindo threads e reunindo resultados
← Voltar para Learn Rust Coding