vector
主要特点:
创建vector
1. 使用new来创建:
fn main() {
let v: Vec<i32> = Vec::new();
}
通常,我们会用初始值来创建一个 Vec 而 Rust 会推断出储存值的类型,所以很少会需要这些类型注解。为了方便 Rust 提供了 vec! 宏,这个宏会根据我们提供的值来创建一个新的 vector。
2. 使用vec宏来创建:
fn main() {
let v = vec![1, 2, 3];
}
因为我们提供了 i32 类型的初始值,Rust 可以推断出 v 的类型是 Vec,因此类型注解就不是必须的。接下来让我们看看如何修改一个 vector。
更改vector
增加元素:
fn main() {
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
}
删除vector
对于vector的删除,就是当超出vector作用域时,vector就会被删除,连带着其所有元素也会被删除。
查找vector
有两种方法引用 vector 中储存的值:通过索引或使用 get 方法。在接下来的示例中,为了更加清楚的说明,我们已经标注了这些函数返回的值的类型。
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {third}");
let third: Option<&i32> = v.get(2);
match third {
Some(third) => println!("The third element is {third}"),
None => println!("There is no third element."),
}
}
当索引超过了vector的范围,也就是发生了越界,那么我们运行程序,就会发生报错,出现panic!
但是如果我们使用下面的方法,由于get方法返回值是Opton枚举的缘故,会返回None的结果,不会产生报错,而是输出“There is no third element.”。
回忆一下不能在相同作用域中同时存在可变和不可变引用的规则。当我们获取了 vector 的第一个元素的不可变引用并尝试在 vector 末尾增加一个元素的时候,如果尝试在函数的后面引用这个元素是行不通的:
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6);
println!("The first element is: {first}");
}
代码看起来应该能够运行:为什么第一个元素的引用会关心 vector 结尾的变化?不能这么做的原因是由于 vector 的工作方式:在 vector 的结尾增加新元素时,在没有足够空间将所有元素依次相邻存放的情况下,可能会要求分配新内存并将老的元素拷贝到新的空间中。这时,第一个元素的引用就指向了被释放的内存。借用规则阻止程序陷入这种状况。
遍历vector中的元素
寻常遍历:
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("{i}");
}
}
遍历可变vector并改变:
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
}
枚举来存储多种类型
vector 只能储存相同类型的值。这是很不方便的;当需要在 vector 中储存不同类型值时,我们可以定义并使用一个枚举!
fn main() {
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
}
String
新建字符串
let mut s = String::new();
可以使用 to_string
方法,它能用于任何实现了 Display trait
的类型,比如字符串字面值。
let data = "initial contents";
let s = data.to_string();
// 该方法也可直接用于字符串字面值:
let s = "initial contents".to_string();
也可以使用 String::from
函数来从字符串字面值创建 String。
let s = String::from("initial contents");
更新字符串
let mut s = String::from("foo");
s.push_str("bar");
ush_str
方法采用字符串 slice,因为我们并不需要获取参数的所有权。
所以下面的代码可通过编译:
let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(s2);
println!("s2 is {s2}");
如果 push_str
方法获取了 s2 的所有权,就不能在最后一行打印出其值了。
push 方法被定义为获取一个单独的字符作为参数,并附加到 String 中。
let mut s = String::from("lo");
s.push('l');
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // 注意 s1 被移动了,不能继续使用
执行完这些代码之后,字符串 s3 将会包含 Hello, world!。s1 在相加后不再有效的原因,和使用 s2 的引用的原因,与使用 + 运算符时调用的函数签名有关。+ 运算符使用了 add
函数,这个函数签名看起来像这样:
fn add(self, s: &str) -> String {
索引字符串
Rust 的字符串不支持索引。原因我就省略了,追根求源点这里–>使用字符串存储UTF-8编码的文本
字符串Slice
let hello = "Здравствуйте";
let s = &hello[0..4];
这里,s 会是一个 &str,它包含字符串的头四个字节。早些时候,我们提到了这些字母都是两个字节长的,所以这意味着 s 将会是 “Зд”。
如果获取 &hello[0..1]
会发生什么呢?答案是:Rust 在运行时会 panic,就跟访问 vector 中的无效索引时一样:
$ cargo run
Compiling collections v0.1.0 (file:///projects/collections)
Finished dev [unoptimized + debuginfo] target(s) in 0.43s
Running `target/debug/collections`
thread 'main' panicked at 'byte index 1 is not a char boundary; it is inside 'З' (bytes 0..2) of `Здравствуйте`', src/main.rs:4:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
你应该小心谨慎地使用这个操作,因为这么做可能会使你的程序崩溃。
遍历字符串
操作字符串每一部分的最好的方法是明确表示需要字符还是字节。对于单独的 Unicode
标量值使用 chars 方法。对 “Зд” 调用 chars
方法会将其分开并返回两个 char 类型的值,接着就可以遍历其结果来访问每一个元素了:
#![allow(unused)]
fn main() {
for c in "Зд".chars() {
println!("{c}");
}
}
З
д
另外 bytes 方法返回每一个原始字节,这可能会适合你的使用场景:
for b in "Зд".bytes() {
println!("{b}");
}
208
151
208
180
不过请记住有效的 Unicode
标量值可能会由不止一个字节组成。
从字符串中获取如同天城文这样的字形簇是很复杂的,所以标准库并没有提供这个功能。crates.io
上有些提供这样功能的 crate。
HashMap
创建HashMap
use std::collections::HashMap;
let mut scores = HashMap::new();
插入键值对
scores.insert(String::from("Yellow"), 50);
查找索引
fn main() {
use std::collections::HashMap;
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).copied().unwrap_or(0);
}
get
方法返回 Option<&V>
,如果某个键在哈希 map 中没有对应的值,get
会返回 None
。程序中通过调用 copied
方法来获取一个 Option<i32>
而不是 Option<&i32>
,接着调用 unwrap_or
在 scores
中没有该键所对应的项时将其设置为零。
遍历查找
fn main() {
use std::collections::HashMap;
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}");
}
}
哈希 map 和所有权
对于像 i32 这样的实现了 Copy trait
的类型,其值可以拷贝进哈希 map。对于像 String 这样拥有所有权的值,其值将被移动而哈希 map 会成为这些值的所有者,如示例所示:
fn main() {
use std::collections::HashMap;
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// 这里 field_name 和 field_value 不再有效,
// 尝试使用它们看看会出现什么编译错误!
}
更新哈希 map
覆盖一个值
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
只在键没有对应值时插入键值对
entry
函数的返回值是一个枚举,Entry
,它代表了可能存在也可能不存在的值。比如说我们想要检查黄队的键是否关联了一个值。如果没有,就插入值 50,对于蓝队也是如此。
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);
{"Yellow": 50, "Blue": 10}
根据旧值更新一个值
use std::collections::HashMap;
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, "hello": 1, "wonderful": 1}
。你可能会看到相同的键值对以不同的顺序打印:回忆一下“访问哈希 map 中的值”部分中遍历哈希 map 会以任意顺序进行。
split_whitespace
方法返回一个由空格分隔 text 值子 slice 的迭代器。or_insert
方法返回这个键的值的一个可变引用(&mut V)。这里我们将这个可变引用储存在 count 变量中,所以为了赋值必须首先使用星号(*)解引用 count。这个可变引用在 for 循环的结尾离开作用域,这样所有这些改变都是安全的并符合借用规则。
原文地址:https://blog.csdn.net/zdsey/article/details/134697384
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_39748.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!