9.常见集合

一、三种常见集合

  • 字符串(string)是字符的集合;
  • vector:一个挨着一个地储存一系列数量可变的值;
  • 哈希map(hash map):将值与一个特定的键(key)相关联;

其它类型的集合参见:https://rustwiki.org/zh-CN/std/collections

二、Vector

2.1 特性

  • 允许在一个单独的数据结构中储存多个值;
  • 所有值在内存中彼此相邻排列;
  • vector 只能储存相同类型的值。

2.2 创建并更新Vector

  • 使用Vec::new()创建;
  • 使用vec!宏创建;
  • 使用push压入数据;
fn main() {
    let mut x = Vec::new(); //创建可变的空Vector
    x.push(38);                       //压入数据

    let y = vec![0, 5, 18, 19];  //使用宏创建,直接存入初始数据
    // y.push(40);  //非可变,不可压入
}

2.3 读取Vector中的元素

  • 使用&[i]返回引用
  • 使用get方法返回一个Option<&T>

&[i]返回

fn main() {
 	let v = vec![1, 2, 3, 4, 5];
 	let v8 = &v[8];
}

上面的代码运行时会报错,根据提示可知,索引超出范围了。
在这里插入图片描述

get方法返回

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    let v9 = v.get(9);
    println!("v9 = {:#?}", v9);
}

上面的代码输出v9 = None ,代表没有找到,由于get方法返回Option<&T>,所以可以使用match匹配;

完整示例

  • 使用get时用match匹配,超出索引时输出错误信息
fn main() {
let v = vec![1, 2];

let third: &i32 = &v[1];
println!("The first element is {}", third);

match v.get(3) {
    Some(third) => println!("The third element is {}", third),
    None => println!("There is no third element."),
}
}

更多的信息参阅:https://doc.rust-lang.org/stable/nomicon/vec/vec.html

2.4 遍历元素

//遍历Vector
fn display_vec(src: &Vec<i32>)
{
    for item in src{
        println!("{}", item);
    }
}

fn main() {
    let mut v = vec![100, 32, 57];
    display_vec(&v);

    for item in &mut v{
        *item +=  10;   //每一项都加10
    }

    display_vec(&v);
}

2.5 储存不同类型的值

  • 一般来说vector存储的数据类型必须相同
  • 可以使用枚举的附加值属性存储不同类型值;

下面的代码表示从Excel中获取一行数据值,这一行值有整数,浮点数及字符串,这样就能存储不同类型的值。

enum SpreadsheetCell {
    Int(i32),
    Float(f64),
    Text(String),
}

fn main() {
    let row = vec![
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Text(String::from("blue")),
        SpreadsheetCell::Float(10.12),
    ];
}

三、字符串

3.1 概念

  • Rust的核心语言中只有一种字符串类型:str,即字符切片&str,它被储存在程序的二进制输出中;
  • String由标准库提供,它是可增长、可变、有所有权以及UTF8编译的字符串类型;
  • 通常说的“字符串”,一般是string或者字符切片
  • 标准库中还包含一系列其他字符串类型,比如OsString、OsStr、CString和CStr,不同的后缀代表它是String或&str的变体;

3.2 新建

  • 创建一个空的然后写入;
  • 从字符串字面量转换;
  • 将字符串字面量转换成String;
fn main() {
    let a = String::new();              //创建空的
    let b = String::from("hello");      //从字符串字面量转换而来
    let c = "hello".to_string();        //将字符串字面量转换成String
}

字符串是UTF8编译的,可以包含任何正确编码的数据

不同语言的“你好"(还是中文的最好看)

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

3.2 更新

  • 使用push_strpush附加;
  • 使用+或者format!宏拼接;

附加更新

fn main() {
    let mut s = String::new();
    s.push('H');                  //附加一个字符
    s.push_str(" Zhong");     //附加一串字面量

    println!("s = {}", s);       //s = H Zhong
}

拼接更新

  • 使用+拼接会转移运算符前面变更的所有权
  • 运算符后面参数用引用
  • format!宏用起来更灵活,不会获取任何参数的所有权
fn main() {
    let s1 = String::from("NiHao");
    let s2: String = String::from("China!");

    let s3 = s1 + &s2;    //获取s1的所有权后拼接上s2的内容,返回所有权

    let s4 = format!("{} {}, I love {}", s2, s2, s2);
    // println!("s1 = {}", s1);    //s1的所有权不在这里了,无法打印
    println!("s2 = {}", s2);       //s2 = China!
    println!("s3 = {}", s3);       //s3 = NiHaoChina!
    println!("s4 = {}", s4);       //s4 = China! China!, I love China!
}

3.3 索引字符串

Rust无法用索引获取字符串,如

fn main() {
    let s1 = String::from("NiHao");
    let x0 = s1[0];
}

报错信息如下在这里插入图片描述

3.4 字符串切片

Rust不支持索引字符串,但是支持字符串切片,如

fn main() {
    let s1 = String::from("NiHao"); 
    println!("{} {}", &s1[..1], &s1[2..5]);
}

3.5 字符串遍历

  • chars方法:返回字符
  • bytes方法:返回原始字节
fn main() {
    let s1 = String::from("NiHao");
    
    for c in s1.chars() {
        println!("{}",c);
    }
    println!("************");
    for c in s1.bytes() {
        println!("{}",c);
    }
}

运行结果
在这里插入图片描述

四、哈希map

4.1 基本概念

  • 哈希map(hash map)使用HashMap<K, V>储存键值对;
  • 可以用于需要任何类型作为键来寻找数据;
  • 哈希map中所有的键必须是相同类型,值也必须都是相同类型
  • 将诸如拥有所有权的String插入hash map,其所有权也会被转移

4.2 新建哈希map

  • 使用new创建空的,然后使用insert增加元素;
  • 使用一个元组的vector的collect方法(其中每个元组包含一个键值对);
  • 使用collect方法时必须显式指定
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();   //创建空hash map,然后插入

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    let teams  = vec![String::from("Blue"), String::from("Yellow")];
    let initial_scores = vec![10, 50];

    let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();  //由两个vector一对一组成hash map
}

所有权被改变示例

use std::collections::HashMap;

fn main() {
    let field_name = String::from("Favorite color");
    let field_value = String::from("Blue");
    
    let mut map = HashMap::new();
    map.insert(field_name, field_value);
    
    println!("field_name = {}", field_name);
    println!("field_value = {}", field_value);
}

编译出错
在这里插入图片描述

4.3 访问哈希map中的值

  • 通过get方法访问
  • 遍历访问

get方法

  • get方法返回Option<V>,结果被装进Some中,如果键没有对应的值,就会返回None。
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);
    
    let team_name = String::from("Blue");
    let score = scores.get(&team_name);
}

遍历方法

use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);
    
    for (key, value) in &scores {
        println!("{}: {}", key, value);
    }
}

运行结果

Yellow: 50
Blue: 10

4.4 更新哈希map

  • 覆盖值
  • 不存在时插入
  • 根据旧值更新三种情况

覆盖值

use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Blue"), 50);   // 强制更新
    
    println!("{:?}", scores);  //{"Blue": 50}
}

不存在时插入

  • entry可以将想要检查的键作为参数,返回枚举Entry
  • or_insert方法在键对应的值存在时就返回这个值的可变引用(&mut V),如果不存在则将参数作为新值插入并返回新值的可变引用
  • 使用entry配合or_insert可以达到目的;
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.entry(String::from("Yellow")).or_insert(50);  //”Yellow"如果不存在,插入  "Yellow:50"
    scores.entry(String::from("Blue")).or_insert(50);    //”Blue"如果不存在,插入  "Blue:50"

    println!("{:?}", scores);  //{"Yellow": 50, "Blue": 10}
}

根据旧值更新

代码统计单词在一句话中出现的次数

use std::collections::HashMap;

fn main() {
    let text = "hello world wonderful world";

    let mut map = HashMap::new();
    
    for word in text.split_whitespace() {
        let count = map.entry(word).or_insert(0);
        *count += 1;
    }
    
    println!("{:?}", map);  //{"world": 2, "wonderful": 1, "hello": 1}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贱贱的剑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值