English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Coleções e Strings no Rust

A coleção (Collection) é a forma mais comum de armazenamento de dados em estruturas de dados, a biblioteca padrão do Rust oferece tipos de coleções ricos para ajudar os desenvolvedores a lidar com operações de estruturas de dados.

Vetor

O vetor (Vector) é uma estrutura de dados unidimensional que armazena múltiplos valores, essa estrutura armazena valores do mesmo tipo linearmente na memória.

O vetor é uma lista linear, representada em Rust como Vec<T>.

A forma de usar o vetor é semelhante à de uma lista (List), podemos criar vetores de tipos específicos dessa forma:

let vector: Vec<i32>= Vec::new(); // Criando um tipo de32 vetor vazio
let vector = vec![1, 2, 4, 8];     // Criando vetores através de arrays

Nós usamos frequentemente operações de adição em listas lineares, mas a adição e a operação push da pilha são essencialmente iguais, então o vetor tem apenas o método push para adicionar um único elemento:

fn main() {
    let mut vector = vec![1, 2, 4, 8];
    vector.push(16);
    vector.push(32);
    vector.push(64);
    println!("{:?}", vector);
}

Resultado da Execução:

[1, 2, 4, 8, 16, 32, 64]

O método append é usado para concatenar um vetor ao final de outro vetor:

fn main() {
    let mut v1: Vec<i32>= vec![1, 2, 4, 8];
    let mut v2: Vec<i32>= vec![16, 32, 64];
    v1.append(&mut v2);
    println!("{:?}", v1);
}

Resultado da Execução:

[1, 2, 4, 8, 16, 32, 64]

O método get é usado para obter valores do vetor:

fn main() {
    let mut v = vec![1, 2, 4, 8];
    println!("{}", match v.get(0) {
        Some(value) => value.to_string(),
        None => "None".to_string()
    });
}

Resultado da Execução:

1

Como o comprimento do vetor não pode ser deduzido lógica, o método get não pode garantir que certamente obtenha um valor, portanto, o valor de retorno do método get é o enum de Option, que pode estar vazio.

Esta é uma maneira segura de obter valores, mas é um pouco complicado de escrever. Se você puder garantir que o índice de obtenção não exceda o intervalo de índices de obtenção do vetor, você também pode usar a sintaxe de obtenção de array:

fn main() {
    let v = vec![1, 2, 4, 8];
    println!("{}", v[1]);
}

Resultado da Execução:

2

Mas se tentarmos obter v[4], então o vetor retornará um erro.

Varredura de vetor:

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
            println!("{}", i);
    }
}

Resultado da Execução:

100
32
57

Se precisar de alterar o valor da variável durante a iteração:

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
}

String

Strings (String) até o presente capítulo já foram usados muitas vezes, então muitos métodos já são conhecidos pelos leitores. Este capítulo principal introduz métodos de string e UTF-8 Propriedades.

Novo string:

let string = String::new();

Conversão de tipos básicos para string:

let one = 1.to_string();         // Número inteiro para string
let float = 1.3.to_string();     // Número float para string
let slice = "slice".to_string(); // Fatia de string para string

Contendo UTF-8 Cadeia de caracteres:

let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");

Adição de string:

let mut s = String::from("run");
s.push_str("oob"); // Adicionar fatia de string
s.push('!');       // Adicionar caractere

Usar + Juntar strings por caractere:

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;

Esta sintaxe também pode incluir fatias de strings:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = s1 + "-" + &s2 + "-" + &s3;

Usar o macro format!:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}",-{}-{}", s1, s2, s3);

Comprimento da string:

let s = "hello";
let len = s.len();

Aqui o valor de len é 5.

let s = "你好";
let len = s.len();

Aqui o valor de len é 6porque o chinês é UTF-8 codificados, cada caractere tem 3 bytes, então o comprimento é6mas o Rust suporta UTF-8 objeto de caractere, então, se você quiser contar o número de caracteres, você pode primeiro transformar a string em um conjunto de caracteres:

let s = "hello你好";
let len = s.chars().count();

Aqui o valor de len é 7porque há 7 O número de caracteres. A velocidade de contagem de caracteres é muito mais lenta do que a de contagem de comprimento.

Iterar sobre a string:

fn main() {
    let s = String::from("hello中文");
    for c in s.chars() {
        println!("{}", c);
    }
}

Resultado da Execução:

h
e
l
l
o
中
文

Pegar um caractere individual da string:

fn main() {
    let s = String::from("EN中文");
    let a = s.chars().nth(2);
    println!("{:?}", a);
}

Resultado da Execução:

Some('中')

Atenção:a função nth é o método de extrair um valor de um iterador, não use assim durante a iteração! Porque UTF-8 A largura de cada caractere não é necessariamente igual!

Se você quiser cortar uma string substring:

fn main() {
    let s = String::from("EN中文");
    let sub = &s[0..2];
    println!("{}", sub);
}

Resultado da Execução:

EN

Mas, note que essa forma pode quebrar um UTF-8 Caracter! Isso gerará um erro:

fn main() {
    let s = String::from("EN中文");
    let sub = &s[0..3];
    println!("{}", sub);
}

Resultado da Execução:

a thread 'main' panicou ao 'byte index' 3 não é um limite de caractere; está dentro de '中' (bytes 2..5) do `EN中文`, src\libcore\str\mod.rs:2069:5 
nota: execute com `RUST_BACKTRACE=1`1varável de ambiente para exibir um rastreamento de backtrace.

Tabela de mapeamento

A tabela de mapeamento (Map) existe amplamente em outros idiomas. A mais amplamente aplicada é a tabela de mapeamento de dispersão de chave-valor (Hash Map).

Crie um novo mapeamento de valor de hash:

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", ""10 m^2");
    println!("{}", map.get("color").unwrap());
}

Atenção: Aqui não foi declarado o generics do hash map devido ao mecanismo de tipo de auto-judgment do Rust.

Resultado da Execução:

red

Os métodos insert e get são os dois métodos mais usados no mapeamento.

O mapeamento suporta iteradores:

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", ""10 m^2");
    for p in map.iter() {
        println!("{:?}", p);
    }
}

Resultado da Execução:

("color", "red") 
("size", ""10 m^2)

Os elementos iterados são tuplas que representam pares de chave-valor.

O mapeamento do Rust é uma estrutura de dados muito conveniente, quando você adiciona novos pares de chave-valor usando o método insert, se já existir uma chave idêntica, o valor correspondente será substituído diretamente. Se você quiser "inserir de forma segura", é quando você confirma que não existe uma chave específica antes de executar a ação de inserção, você pode fazer assim:

map.entry("color").or_insert("red");

Esta frase significa que, se não houver um par de chave-valor com a chave "color", adicionará um e configurará o valor como "red", caso contrário, passará.

Se você já souber que existe uma chave específica e quiser modificar diretamente o valor correspondente, há uma maneira mais rápida:

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert(1, "a");
    
    if let Some(x) = map.get_mut(&1) {
        *x = "b";
    }
}