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

Rust 集合与字符串

集合(Collection)是数据结构中最普遍的数据存放形式,Rust 标准库中提供了丰富的集合类型帮助开发者处理数据结构的操作。

向量

向量(Vector)是一个存放多值的单数据结构,该结构将相同类型的值线性的存放在内存中。

向量是线性表,在 Rust 中的表示是 Vec<T>。

向量的使用方式类似于列表(List),我们可以通过这种方式创建指定类型的向量:

let vector: Vec<i32> = Vec::new(); // 创建类型为 i32 的空向量
let vector = vec![1, 2, 4, 8]; // 通过数组创建向量

Usiamo spesso l'operazione di appendere nelle liste lineari, ma l'appendere e l'operazione push dello stack sono essenzialmente le stesse, quindi l'array ha solo il metodo push per accodare un singolo elemento:

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

运行结果:

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

Il metodo append viene utilizzato per accodare un array all'altro array:

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);
{}

运行结果:

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

Il metodo get viene utilizzato per estrarre valori dall'array:

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

运行结果:

1

Poiché la lunghezza dell'array non può essere dedotta logicamente, il metodo get non può garantire che一定能获取到值,quindi il valore di ritorno del metodo get è l'enumerazione di tipo Option, che potrebbe essere vuoto.

Questo è un metodo sicuro per estrarre valori, ma è un po' complicato da scrivere. Se puoi garantire che l'indice di estrazione non superi l'intervallo degli indici dell'array, puoi anche utilizzare la sintassi di accesso agli array:

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

运行结果:

2

Ma se proviamo a ottenere v[4], l'array restituirà un errore.

Iterare l'array:

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

运行结果:

100
32
57

Se durante l'iterazione è necessario modificare il valore della variabile:

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

Stringa

La classe di stringa (String) è stata utilizzata molto fino ad ora, quindi molte delle sue funzioni sono già familiari ai lettori. Questo capitolo introduce principalmente le funzioni delle stringhe e le proprietà UTF-8.

新建字符串:

let string = String::new();

基础类型转换成字符串:

let one = 1.to_string(); // 整数到字符串
let float = 1.3.to_string(); // 浮点数到字符串
let slice = "slice".to_string(); // 字符串切片到字符串

包含 UTF-8 字符的字符串:

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");

字符串追加:

let mut s = String::from("run");
s.push_str("oob"); // 追加字符串切片
s.push('!'); // 追加字符

用 + 号拼接字符串:

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

这个语法也可以包含字符串切片:

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

使用 format! 宏:

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

Lunghezza della stringa:

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

Il valore di len è 5.

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

Il valore di len è 6. Poiché i caratteri cinesi sono codificati in UTF-8, ogni carattere ha una lunghezza di 3 byte, quindi la lunghezza è 6. Ma Rust supporta gli oggetti di caratteri UTF-8, quindi se si desidera contare il numero di caratteri, è possibile prendere inizialmente la stringa come un insieme di caratteri:

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

Il valore di len è 7, perché ci sono in totale 7 caratteri. La velocità di conteggio dei caratteri è molto più lenta rispetto a quella di conteggio della lunghezza.

Estrazione di una stringa:

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

运行结果:

h
e
l
l
o
中
文

Estrazione di un singolo carattere dalla stringa:

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

运行结果:

Some('中')

注意La funzione nth è il metodo per estrarre un valore da un iteratore, non usarla così durante la scansione! Poiché ogni carattere UTF-8 non ha la stessa lunghezza!

Se si desidera estrarre una sottostringa di stringa:

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

运行结果:

EN

Ma si prega di notare che tale uso potrebbe rompere un carattere UTF-8! Ciò causerebbe un errore:

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

运行结果:

Il thread 'main' è panico per 'byte index 3 is not a char boundary; it is inside' 中 'bytes 2..5) of `EN中文`', src\libcore\str\mod.rs:2069:5 
note: eseguire con la variabile d'ambiente `RUST_BACKTRACE=1` per visualizzare un backtrace.

Tabella di mappatura

La tabella di mappatura (Map) esiste ampiamente in altre lingue. Quella più comune è la tabella di mappatura a hash (Hash Map).

新建一个散列值映射表:

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());
{}

注意:这里没有声明散列表的泛型,是因为 Rust 的自动判断类型机制。

运行结果:

red

insert 方法和 get 方法是映射表最常用的两个方法。

映射表支持迭代器:

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);
    {}
{}

运行结果:

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

迭代元素是表示键值对的元组。

Rust 的映射表是十分方便的数据结构,当使用 insert 方法添加新的键值对的时候,如果已经存在相同的键,会直接覆盖对应的值。如果你想"安全地插入",就是在确认当前不存在某个键时才执行的插入动作,可以这样:

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

这句话的意思是如果没有键为 "color" 的键值对就添加它并设定值为 "red",否则将跳过。

在已经确定有某个键的情况下如果想直接修改对应的值,有更快的办法:

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";
    {}
{}