rust 初探 -- 常用的集合

avatar
作者
猴君
阅读量:0

rust 初探 – 常用的集合

Vector

存储在堆内存上的数据,运行时可以动态变大或者变小。
Vec 特性:

  • 由标准库提供,可以存储多个相同类型的值,并且值在内存中连续存放

Vector 的创建

fn main() {     // Vec::new()     let v: Vec<i32> = Vec::new();     // 使用初始值创建,使用 vec! 宏     let v1 = vec![1,2,3]; } 

更新 Vector

fn main() {     //这里不需要指明 vec 的类型,因为后面有 push 操作会自己推断出来     let mut v = Vec::new();     v.push(1); } 

删除 Vector

和其他的 struct 结构体一样,当 Vector 离开了作用域,就会被清理掉
如果涉及到引用会不一样。

读取 Vector 的元素

fn main() {     let v = vec![1,2,3,4,5];     let third = &v[2]; // 1. 使用索引,非法访问 panic     println!("{}", third);      match v.get(2) { // 2. get 方法,非法访问 返回 None         Some(third) => println!("get {}", third),         None => println!("not exist"),     } } 
所有权和借用规则

不能在同一作用域里,对一个值不能同时有可变和不可变的引用

//vec 中内存中是连续的,新增的时候可能会重新分配,所以直接不让这样操作 fn main() {     let mut v = vec![1,2,3,4,5];     let third = &v[2]; //不可变的          v.push(6); //mutable borrow occurs here      println!("{}", third); } 
遍历 Vector 的值
fn main() { 	let mut v = vec![1,2,3,4,5]; 	for i in &mut v { 		*i += 50; 	} 	for i in v { 		println!("{}", i); 	} } 
使用 enum 来存储多种数据类型
  • enum 的变体可以附加不同类型的数据
  • enum 的变体定义在同一个 enum 类型下
enum Cell { 	Int(i32), 	Float(f64), 	Text(String), } // 因为类型不同,枚举的时候不好操作(很多个),需要使用到 trait 对象 fn main() { 	//编译时就知道堆上要多大的内存,而且知道所有的可能情况,编译时可以做检查 	let row = vec![ 		Cell::Int(3), 		Cell::Float(10.1), 		Cell::Text(String::from("text")), 	]; } 

字符串是什么

  • Rust 的核心语言层面,只有一个字符串类型:字符串切片 str(或&str)

  • 字符串切片:对存储在其他地方、UTF-8编码的字符串的引用

    • 字符串字面值:存储在二进制文件中,也是字符串切片
  • String 类型:

    • 来自标准库而不是核心语言
    • 可增长、可修改、可拥有

通常说的字符串是指?

String 和 &str

  • 特性:utf-8 编码

其他类型的字符串

  • OsString,OsStr,CString,Cstr
  • 还有一些其他第三方库

创建一个新的字符串

String::new()//用于创建一个空的字符串,是可变的 to_string()	//方法,可用于实现了 displag trait 的类型,包括字符串字面值 String::from() //函数,从字面值来创建字符串 

更新 String

  • push_str() 方法:字符串切片
fn main() { 	let mut s1 = String::from("foo"); 	s1.push_str("bar");//- push_str() 方法:字符串切片  	println!("{}", s1); // foobar  	s1.push('b');//- push() 方法:单个字符 	println!("{}", s1); // foobarb } 
    • 操作符,拼接字符串
fn main() { 	let s1 = String::from("foo"); 	let s2: String = String::from("bar"); 	 	let s3 = s1 + &s2; 	//相当于 fn add(self, s: &str) -> String {} 	//&String 强制转换成 &str,解引用强制转换(deref coercion),会保留 s2 的所有权  	println!("{}", s3); 	// println!("{}", s1);//error[E0382]: borrow of moved value: `s1` 	// println!("{}", s2); } 
  • format!:不会取得任意参数的所有权
use std::fmt::format;  fn main() { 	let s1 = String::from("foo"); 	let s2: String = String::from("bar"); 	let s3: String = String::from("car"); 	 	// let s4 = s1 + "-" + &s2 + "-" + &s3; 	// println!("{}", s4); //foo-bar-car 	 	let s5 = format!("{}-{}-{}", s1, s2, s3); 	println!("{}", s5);//foo-bar-car } 

内部表示

  • String 是对 Vex 的包装
 String::from("hola").len(); //4,返回字节数  // unicode 标量值 
字节,标量值,字形簇
fn main() { 	let w = "测试一下"; 	for b in w.bytes() {//字节 		print!("{} ", b)//230 181 139 232 175 149 228 184 128 228 184 139  	} 	for b in w.chars() {//标量值 		print!("{} ", b)// 测 试 一 下 	} } 
访问 String
  • 不支持按索引语法形式进行访问:
    • 不同语言的字符串,其对应的字节数不同
    • 索引操作应消耗一个常量时间(O(1)),而String 无法保证,需要遍历所有内容来确定有多少个合法的字符
切割 String
s = &hello[0..4]; //但是切割必须沿着字符的边界切割,否则会panic 

HashMap<K, V>

  • 键值对的形式存储数据
  • 适合场景,通过 K (任何类型)来寻找数据,而不是通过索引

创建 HashMap

use std::collections::HashMap;  fn main() { 	//创建 HashMap 	let mut scores = HashMap::new(); 	scores.insert(String::from("bob"), 99); //会基于此推断 k,v的类型 	// 不在 Prelude 中,所以需要添加 use  	 	//2. collect() 	let team = vec![String::from("a"), String::from("b")]; 	let t_scores = vec![10,12]; 	let hp: HashMap<_, _> = team.iter().zip(t_scores.iter()).collect(); 	// 需要指明 HashMap<_, _> } 
  • 数据存储在 heap 上
  • 同构的:一个 HashMap 中,所有 k 必须是同一类型,所有 v 必须是同一类型

HashMap 和所有权

  • 对于实现了 Copy trait 的类型,值会被复制到 HashMap 中
  • 对于拥有所有权的值(如 String),值会被移动,所有权会被转移给 HashMap
  • 如果将值的引用插入到 HashMap,值本身不会移动 (被引用的值需要有效)
fn main() { 	let name = String::from("key"); 	let value = String::from("value");  	//创建 HashMap 	let mut scores = HashMap::new(); 	// scores.insert(name, value);  	// print!("{}:{}", name, value); // value borrowed here after move 	scores.insert(&name, &value);  	println!("{}:{}", name, value);//key:value } 

访问 HashMap

  • get 方法,参数 K,返回 Option<&V>
use std::collections::HashMap;  fn main() { 	//创建 HashMap 	let mut scores = HashMap::new(); 	scores.insert(String::from("bob"), 90); 	scores.insert(String::from("lili"), 100);  	let name = String::from("bob"); 	let score = scores.get(&name);  	match score { 		Some(s) => println!("{}", s), // 90 		None => println!("team not exist"), 	}; }  

遍历 HashMap

use std::collections::HashMap;  fn main() { 	//创建 HashMap 	let mut scores = HashMap::new(); 	scores.insert(String::from("bob"), 90); 	scores.insert(String::from("lili"), 100);  	for (k, v) in &scores { 		println!("{}-{}", k, v)//lili-100 bob-90 	} } 

更新 HashMap

  • HashMap 大小可变,每个 K 只能对应一个 V
  • 更新 HashMap 中的数据,已存在 K,或者不存在 K
use std::collections::HashMap;  fn main() { 	//创建 HashMap 	let mut scores = HashMap::new(); 	scores.insert(String::from("bob"), 90); 	scores.insert(String::from("lili"), 100);  	//1. 替换现有的 v,插入两个相同k,不同 v,前者会被后者替换 	//2. 只在 K 不存在时,才插入 v 	//使用 entry 方法,结合 or_insert  	scores.entry(String::from("bob")).or_insert(80); 	scores.entry(String::from("bob2")).or_insert(80);  	println!("{:#?}", scores) } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!