Desafio Rust

Gerenciando múltiplos donos com move e clone

Enunciado

Você tem um Vec<String> com nomes. Crie uma função processa que recebe o vetor por valor, itera sobre ele e, para cada nome, imprime o nome e seu comprimento. A função deve consumir o vetor. No main, crie o vetor, faça um clone antes de chamar processa, e depois imprima o vetor original para provar que ele ainda está disponível.

Requisitos

  • A função processa deve receber Vec<String> e retornar ().
  • O main deve clonar o vetor antes de passá-lo para processa.
  • Após a chamada, o vetor original deve ser impresso com {:?}.
  • A saída deve listar cada nome e seu tamanho, seguida do vetor original.

Código inicial

fn main() {
    let nomes = vec![
        String::from("Ana"),
        String::from("Bruno"),
        String::from("Carla"),
    ];
    // clone, chame processa e imprima o original
}

fn processa(v: Vec<String>) {
    // implemente
}

Saída esperada

Ana tem 3 letras
Bruno tem 5 letras
Carla tem 5 letras
Original: ["Ana", "Bruno", "Carla"]
Ver dica

Use nomes.clone() para criar uma cópia do vetor antes de mover. Dentro de processa, itere com for nome in v e use nome.len().

Mostrar solução
fn main() {
    let nomes = vec![
        String::from("Ana"),
        String::from("Bruno"),
        String::from("Carla"),
    ];

    let copia = nomes.clone(); // cópia profunda do vetor e das strings
    processa(copia); // move a cópia para a função

    // nomes ainda é válido porque só a cópia foi movida
    println!("Original: {:?}", nomes);
}

fn processa(v: Vec<String>) {
    for nome in v { // consome o vetor, movendo cada String
        println!("{} tem {} letras", nome, nome.len());
    }
}

Passo a passo

  1. vec![...] cria um Vec<String> e nomes se torna dona do vetor e das strings internas.
  2. nomes.clone() cria uma cópia profunda: um novo vetor com novas Strings clonadas.
  3. processa(copia) move a posse da cópia para o parâmetro v.
  4. Dentro da função, for nome in v consome o vetor, movendo cada String para nome a cada iteração.
  5. Cada nome é impresso com seu comprimento e depois liberado no fim da iteração.
  6. Após a função, copia foi consumida, mas nomes permanece intacto.
  7. O println! final imprime o vetor original.

Por que funciona

O clone cria uma cópia independente, então o move para processa não afeta nomes. O for sobre Vec<String> consome o vetor, movendo cada elemento; isso é seguro porque a função é dona do vetor. O ownership garante que não há aliasing mutável e que a memória é liberada corretamente.

Erros comuns

  • Esquecer o .clone() e passar nomes diretamente: nomes seria movido e o println! final falharia com use of moved value.
  • Tentar usar copia após processa(copia): também seria um erro de move.
  • Iterar com for nome in &v dentro de processa: funcionaria, mas não consumiria o vetor; o enunciado pede consumo.

Outra forma de resolver

Se não quiser clonar, passe uma referência imutável:

fn processa(v: &[String]) {
    for nome in v {
        println!("{} tem {} letras", nome, nome.len());
    }
}

fn main() {
    let nomes = vec![String::from("Ana"), String::from("Bruno"), String::from("Carla")];
    processa(&nomes);
    println!("Original: {:?}", nomes);
}

Essa é a forma idiomática quando não é necessário consumir o vetor.

Saída esperada

Ana tem 3 letras
Bruno tem 5 letras
Carla tem 5 letras
Original: ["Ana", "Bruno", "Carla"]