Criar listas com Vec

RustBeginner
Pratique Agora

Introdução

Uma variável armazena um valor, mas muitos programas precisam de uma lista ordenada cujo tamanho possa mudar. O Vec<T> do Rust é uma sequência expansível: cada elemento tem o tipo T, os valores mantêm sua ordem e o vetor é proprietário de seus elementos.

Você criará uma lista de pedidos de um café, lerá com segurança uma posição, percorrerá todos os pedidos sem consumir a lista e atualizará cada string armazenada por meio de referências mutáveis.

Criar e expandir um vetor

Nesta etapa, você adicionará três strings próprias a um vetor inicialmente vazio.

Entre no projeto preparado e abra o código-fonte:

cd /home/labex/project/cafe-orders
nano src/main.rs

A declaração Vec<String> significa “um vetor cujos elementos são valores String próprios”. Essa é a mesma notação com colchetes angulares usada para contêineres que você viu em Option<u32>: aqui, o tipo do elemento contido é String. Você aprenderá a definir tipos reutilizáveis desse tipo na Lab posterior sobre genéricos. Vec::new() cria um vetor vazio. A variável é declarada com mut porque adicionar elementos altera o vetor.

Substitua o comentário da Etapa 1 por três chamadas a push:

    orders.push(String::from("Latte"));
    orders.push(String::from("Tea"));
    orders.push(String::from("Cake"));

push adiciona um elemento ao final, preservando a ordem de inserção. Salve com Ctrl+O, pressione Enter e saia com Ctrl+X. Verifique e execute:

cargo check
cargo run --quiet

A saída deverá ser:

Order count: 3
Orders: ["Latte", "Tea", "Cake"]

len() informa que há três elementos. O marcador :? usa a formatação de depuração do Rust para exibir o vetor completo, incluindo as aspas das strings.

Ler uma posição com segurança

Nesta etapa, você lerá a segunda posição do vetor sem correr o risco de um panic por acesso fora dos limites.

As posições de um vetor começam em zero, portanto o índice 1 se refere ao segundo pedido. O método get retorna um Option<&String>: Some contém uma referência compartilhada quando a posição existe, e None representa uma posição ausente. A referência permite ler o elemento enquanto o vetor continua sendo seu proprietário.

Abra o código-fonte:

nano src/main.rs

Substitua o comentário da Etapa 2 por:

    match orders.get(1) {
        Some(order) => println!("Second order: {order}"),
        None => println!("Second order: missing"),
    }

Esse código lê o elemento sem mover sua String para fora do vetor. Salve e saia, depois execute:

cargo run --quiet

Uma nova linha final deverá aparecer:

Second order: Tea

Essa linha comprova que a posição 1 existe e que a ordem de inserção foi preservada.

Percorrer usando uma referência compartilhada

Nesta etapa, você percorrerá todos os pedidos e manterá o vetor disponível depois disso.

Escrever &orders toma emprestado o vetor em vez de movê-lo para dentro do loop for. Portanto, cada valor do loop é uma referência compartilhada a uma String armazenada.

Abra o código-fonte:

nano src/main.rs

Substitua o comentário da Etapa 3 por este loop e pela verificação seguinte:

    for order in &orders {
        println!("Queued: {order}");
    }
    println!("Stored after display: {}", orders.len());

Salve e saia, depois execute:

cargo run --quiet

As novas linhas deverão ser:

Queued: Latte
Queued: Tea
Queued: Cake
Stored after display: 3

A contagem final pode ser usada depois do loop porque o loop tomou o vetor emprestado e devolveu cada referência compartilhada antes de continuar.

Atualizar por meio de referências mutáveis

Nesta etapa, você tomará cada elemento do vetor emprestado de forma mutável e o atualizará no próprio local antes da execução do loop de exibição.

Somente uma referência mutável a um valor pode estar ativa por vez. Um loop for sobre &mut orders segue essa regra ao fornecer uma referência mutável a um elemento, usá-la durante a iteração atual e depois passar ao elemento seguinte.

Abra o código-fonte:

nano src/main.rs

Substitua o comentário da Etapa 4 por:

    for order in &mut orders {
        order.push_str(" - ready");
    }

push_str adiciona texto emprestado a cada String própria. O Rust usa automaticamente a String mutável por trás de cada referência nessa chamada de método.

Salve e saia, depois verifique e execute:

cargo check
cargo run --quiet

A saída completa deverá ser:

Order count: 3
Orders: ["Latte", "Tea", "Cake"]
Second order: Tea
Queued: Latte - ready
Queued: Tea - ready
Queued: Cake - ready
Stored after display: 3

As linhas atualizadas da fila comprovam que todos os elementos foram alterados no próprio local. A contagem final comprova que o vetor ainda é proprietário das mesmas três strings.

Resumo

Você criou e expandiu um Vec<String>, acessou uma posição com segurança usando get, percorreu o vetor sem consumi-lo e atualizou cada elemento por meio de referências mutáveis.