vector
- 由标准库提供
- 可存储多个值
- 只能存储相同类型的数据
- 值在内存中连续存放
- 创建vector
- Vec::new 函数
fn main() { let v: Vec<i32> = Vec::new(); }fn main() { let v = vec![1, 2, 3, 4, 5]; let third: &i32 = &v[2]; println!("The third element is {}", third); match v.get(2) { Some(third) => println!("The third element is {}", third), None => println!("There is no third element."), } } - 更新vector
- 向vector添加元素,使用push方法
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
- 与任何其它struct一样,当vector离开作用域后
- 它就被清理掉了
- 它所有的元素也被清理掉了
- 与任何其它struct一样,当vector离开作用域后
- 获取vector的元素
+
fn main() { let v = vec![1, 2, 3, 4, 5]; let third: &i32 = &v[2]; println!("The third element is {}", third); match v.get(2) { Some(third) => println!("The third element is {}", third), None => println!("There is no third element."), } } - 所有权和借用规则
- 不能在同一作用域内同时拥有可变和不可变引用
fn main() { let mut v = vec![1, 2, 3, 4, 5]; let first = &v[0]; v.push(6); println!("The first element is: {}", first); } $ cargo run Compiling collections v0.1.0 (file:///projects/collections) error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable --> src/main.rs:6:5 | 4 | let first = &v[0]; | - immutable borrow occurs here 5 | 6 | v.push(6); | ^^^^^^^^^ mutable borrow occurs here 7 | 8 | println!("The first element is: {}", first); | ----- immutable borrow later used here For more information about this error, try `rustc --explain E0502`. error: could not compile `collections` due to previous error - 遍历
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
}
- 使用enum来存储多种数据类型
- enum的变体可以附加不同类型的数据
- enum的变体定义在同一个enum的类型下
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
- rust 开发者经常会被字符串困扰的原因
- rust倾向于暴露可能的错误
- 字符串数据结构复杂
- UTF-8
- 字符串是什么
- byte的集合
- 一些方法
- 能将byte 解析为文本
- rust的核心语言层面,只有一个字符串类型:字符串切片str(&str)
- 字符串切片:对存储在其它地方、utf-8编码的字符串的引用
- 字符串字面值:存储在二进制文件,也是字符串切片
- string类型
- 来自标准库而不是核心语言
- 可增长、可修改、可拥有
- utf-8编码
- 通常说的字符串是指
- string和str
- 标准库里用的多
- utf-8编码
- 本节讲的主要是string
- string和str
- 其它类型的字符串
- Rust的标准库还包含了很多其它的字符串类型,例如: osstring, osstr, cstring, cstr
- string vs str 后缀:拥有或借用的变体
- 可存储不同编码的文本或在内存中以不同的形式展现
- libray crate 针对存储字符串可提供更多的选项
- Rust的标准库还包含了很多其它的字符串类型,例如: osstring, osstr, cstring, cstr
- 创建一个新的字符串(String)
- 很多Vec< T >的操作都可用于String
- String::new()函数
- 使用初始值来创建string:
+
fn main() { let data = "initial contents"; let s = data.to_string(); // the method also works on a literal directly: let s = "initial contents".to_string(); } fn main() { let s = String::from("initial contents"); } - 更新string
- push_str()方法:把一个字符串切片附加到string
fn main() { let mut s1 = String::from("foo"); let s2 = "bar"; s1.push_str(s2); println!("s2 is {}", s2); }- push 方法: 单个字符附加到string
fn main() { let mut s = String::from("lo"); s.push('l'); }- +: 连接字符串
- 使用了类似这个签名的方法fn add(self, s:&str) -> String{...}
- 标准库中的add方法使用了泛型
- 只能把&str添加到string
- 解引用强制转换(deref coercion)
- 使用了类似这个签名的方法fn add(self, s:&str) -> String{...}
- format!: 连接多个字符串(例子)
- 和println!()类似,便返回字符串
- 不会获得参数的所有权
fn main() { let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); let s = format!("{}-{}-{}", s1, s2, s3); } fn main() { let s1 = String::from("Hello, "); let s2 = String::from("world!"); let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used }- 对string按索引的形式进行访问
- 按索引语法访问string的某部分,会报错
- Rust的字符串不支持索引语法访问
- 内部表示
- String是对Vec< u8 > 的包装
- len()方法
let hello = "Здравствуйте"; let answer = &hello[0];
- String是对Vec< u8 > 的包装
- 字节、标量值、字形簇 Bytes, Scalar Values, Grapheme Clusters
- Rust 有三种看待字符串的方式:
- 字节
- 标量值
- 字形簇 (最接近所谓的“字母”)
#![allow(unused)] fn main() { for c in "नमस्ते".chars() { println!("{}", c); } }- Rust 不允许对String进行索引的最后一个原因:
- 索引操作应消耗一个常量时间(O(1))
- 而string无法保证:需要遍历所有内容,来确定有多少个合法的字符
- 切割string
- 可以使用【】和一个范围来创建字符会串的切片(例子)
- 必须谨慎使用
- 如果切割时跨越了字符边界,程序就会panic
#![allow(unused)] fn main() { let hello = "Здравствуйте"; let s = &hello[0..4]; }
- 可以使用【】和一个范围来创建字符会串的切片(例子)
- 遍历String的方法
- 对于标量值: chars()方法
- 对于字节: bytes()方法
- 对于字形簇: 很复杂,标准库未提供
- string不简单
-
rust选择将正确处理string数据作为所有rust程序的默认行为
- 程序员必须在处理utf-8数据之前投入更多的精力
-
可防止在开发后期处理涉及及非ascll字符的错误
-
- Rust 有三种看待字符串的方式:
hashmap
- HashMap<k,v>
- 键值对的形式存储数据,一个键(key)对应一个值(Value)
- Hash函数:决定如何在内存中存放K和V
- 适用场景:通过K(任何类型)来寻找数据,而不是通过索引
- 创建HashMap
+
fn main() { use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); }- 创建hashmap:new()函数
- 添加数据:insert()方法
- HashMap
- HashMap用的较少,不在prelude中
- 标准库对其支持罗长,没有内置的宏来创建HashMap
- 数据存储在heap上
- 同构的。一个hashMap中:
- 所有的K必须是同一种类型
- 所有的v必须是同一种类型
- 另一种创建HashMap的方式:collect方法
- 在元素类型为tuple的vector上使用collect方法,可以组建一个HashMap:
- 要求tuple有两个值:一个作为K,一个作为V
- Collect 方法可以把数据融合成很多种集合类型,包括HashMap
- 返回值需要显式指明类型
fn main() { use std::collections::HashMap; let teams = vec![String::from("Blue"), String::from("Yellow")]; let initial_scores = vec![10, 50]; let mut scores: HashMap<_, _> = teams.into_iter().zip(initial_scores.into_iter()).collect(); }
- 在元素类型为tuple的vector上使用collect方法,可以组建一个HashMap:
- HashMap和所有权
- 对于实现了copy trait的类型(例如:i32),值会被复制到hashMap中
- 对于拥有所有权的值(例如String),值会被移动,所有权会转移给HashMap
- 如果将值的引用插入到HashMap,值本身不会移动
- 访问Hashmap的值
- get方法
- 参数:K
- 返回:Option<&v>
- get方法
- 遍历hashmap
+
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); } } - 如何更新HashMap
- HashMap大小可变
- 每个k同时只能对应一个V
- 更新HashMap中的数据
- K已经存在,对应一个v
- 替换现在的V
- 如果向hashMap插入一对KV,然后再插入同样的k,但是不同的v,那么原来的v就会被替换掉
- 保留现有的v,忽略新的v
- 合并现有的v和新的v
- 替换现在的V
- K 不存在
- 添加一对K,V
- 只有K不对应该任何值的情况下,才插入V
- entry方法:检查指定的K是否对应该一个V
- 参数为K
- 返回enum entry:代表值是否存在
- entry的or_insert()方法
- 返回
- 如果K存在,返回到对应的V的一个可变引用
- 返回
- entry方法:检查指定的K是否对应该一个V
- 只有K不对应该任何值的情况下,才插入V
- 添加一对K,V
- K已经存在,对应一个v
- Hash函数
- 默认情况下,HashMap使用加密功能强大的Hash函数,可以抵抗拒绝服务(Dos)攻击
- 不是可用的最快的hash算法
- 但具有更好的安全性
- 可以指定不同的hasher来切换到另一个函数
- hasher是实现buildhasher trait的类型
- 默认情况下,HashMap使用加密功能强大的Hash函数,可以抵抗拒绝服务(Dos)攻击