Rust 知识积累(5)
&str
字符串
- 直接声明时,生命周期为整个程序,直接写进了二进制中,类型为&'static str',意为字符串字元有一个叫static的生命期
借用str
- 作为String的引用来使用,无生命期,例如 fn print_str(my_str: &str){},调用为print_str(&String::format("string""));
生命期
-
引用的生命期不能比这个对象长
fn returns_str() -> &str{ return "I am" // ---错误,因为这个值声明是在方法内,引用出去后是null } // 改进 fn returns_str() -> &‘static str{ return "I am" // ---正确,返回了字符串字面量,该值整个程序有效 }
struct使用
-
基础使用
// 尝试写struct City<'a>和name: &'a str // 意思是 name可以存活到与City一样的生命期 // a可以为任意值 #[derive(Debug)] struct City<'a>{ name: &'a str, date_f: u32, } let my_city = City{ name: &"China".to_string(), date_f: 2022, }
-
添加调用方法
// 不仅仅struct要与name同一个生命期,impl也要一致 struct Adventurer<'a>{ name: &'a str, hit_points: u32, } impl Adventer<'_>{ fn take_damage(&mut self){ slef.hit_points -= 20; println!("{} has {} hit", slef.name, self.hit_points); } } fn main(){ let mut bi = Adventurer{ name:"Billy", hit_points: 100, } bi.take_damage(); }
内部可变性
-
不用mut也可修改数据,例如Cell,RefCell,Mutex, RwLock
-
Cell
// 给出的是值而不是引用 use std::cell::Cell; struct PhoneModel{ on_sale: Cell<bool>, } fn main(){ let huawei_phone = PhoneModel{ on_sale: Cell::new(true), }; huawei_phone.on_sale.set(false); }
-
RefCell
// 引用单元格,引用 // 小心使用,他是运行后编译 use std::cell::RefCell; struce User{ active: RefCell<bool>, } fn main(){ let user_l = user{ active: RefCell::new(true), }; println!("{}", user_l.active); user_l.active.borrow(); user_l.active.borrow_mut(); //引出后就不能再borrow_mut()了 user_l.active.replace(false); }
-
Mutex
线程安全,只让一个线程修改它(有lock())
use std::sync::Mutex; let my_mutex = Mutex::new(5); // 加锁 let mut mutex_changer = my_mutex.lock().unwarp(); // 加锁后修改,也可大括号括起来,括号外自己解锁(超出加锁范围) *mutex_changer = 6; // 解锁 std::mem::drop(mutex_changer); // 判断是否可用 if let Ok(value) = my_mutex.try_lock(){ //没加锁 }else{ // 加锁 } // 直接赋值,不需要解锁 *my_mutex.lock().unwarp() = 6;
-
RwLock
-
读写锁 类似于Mutex和RefCell
-
多个.read() 可以,一个.write() 可以
use std::sync::RwLock; let my_rwlock = RwLock::new(5); let read1 = my_rwlock.read().unwrap(); // 多个read都可以 let read2 = my_rwlock.read().unwrap();// 多个read都可以 drop(read1); drop(read2); // 两个read()都进行了解锁,因此可以write() let mut write1 = my_rwlock.write().unwarp(); *write1 = 6; drop(write1); // 解锁后可继续操作 if let Ok(mut number) = my_rwlock.try_write(){ *number += 10 }else{ // 锁住了 }
-
Cow
-
枚举,写时克隆
// 说明: 当类型为B时,返回 Borrowed(&'a B), 否则 Owned(<B as ToOwned>:Owned) pub enum Cow<'a, B> where B: 'a + ToOwned + ?Size,{ Borrowed(&'a B), Owned(<B as ToOwned>:Owned), } // Cow<'static, str>判断时为 // Cow::Borrowed(message) : message 为 实际值 // Cow::Owned(message) : message 为 实际值 //注意,返回的数值是str fn modulo_3(input: u8) -> Cow<'static, str> { match input % 3 { 0 => "Remainder is 0".into(), 1 => "Remainder is 1".into(), remainder => format!("Remainder is {}", remainder).into(), // 这个为String,因此会变成Cow::Owned() } } fn main() { for number in 1..=6 { match modulo_3(number) { Cow::Borrowed(message) => println!("{} went in. The Cow is borrowed with this message: {}", number, message), Cow::Owned(message) => println!("{} went in. The Cow is owned with this message: {}", number, message), } } }
类型别名
-
声明别名的几种方式及使用
//方式一 type CharacterVec = Vec<char>; //方式二 type SkipFourTakeFive<'a> = std::iter::Take<std::iter::Skip<std::slice::Iter<'a, char>>>; fn returns<'a>(input: &'a Vec<char>) -> SkipFourTakeFive { input.iter().skip(4).take(5) } //方式三 use std::iter::{Task, Skip}; use std::slice::Iter; fn returns<'a>(input: &'a Vec<char>) -> Take<Skip<Iter<'a, char>>> { input.iter().skip(4).take(5) } //方式四 struct File(String); // File is a wrapper around String fn main() { let my_file = File(String::from("I am file contents")); let my_string = String::from("I am file contents"); println!("{}", my_file == my_string); // ⚠️ 错误,不能比较,因为类型不对 println!("{}", my_file.0 == my_string);// 正确 } //方式五 enum枚举简单调用 enum MapDirection{ North, East, } fn main(){ use MapDirection::*; //后面可直接使用 MapDirction match direction{ North => println!(), East => println!(); } // 也可以进行改名 use MapDirection::{ North as N, East as E, } }
todo! 宏
-
还未想好如何操作,但是又要运行,可以用 todo!()
fn get_book(book: &Book) -> Option<String> { todo!() // todo means "I will do it later, please be quiet" }
Rc
-
使用数量变为0,才会消失
use std::rc:Rc; let history = Rc::new("".to_string()); let h2 = history.clone() // Rc的计数变为了2 println!("{}", Rc::strong_count(&history)); //强引用数量 Rc::downgrade(&item) 来创建弱引用 //如果只有弱引用,则变量会消失 Rc::weak_count(&item) 查看弱引用数
多线程
-
std ::thread ::spawn 创建线程
fn main(){ //当主程序结束,线程还未结束时,会报异常 std::thread::spawn(||{ println!(""); }); // 改进 将线程绑定到变量上 let handle = std::thread::spawn(||{ println!(""); }); handle.join(); // 取值 let mut my_str = String::form(""); let handle = std::thread::spawn(move || { // 使用move来获得线程外的数值 println!("{}", my_str); }); handle.join(); }
闭包
-
FnOnce: 取整个值
-
FnMut : 取一个可变引用
-
Fn : 取一个普通引用
-
各种方式举例
// fn方式 let my_str = String::form("string"); let my_closure = || println!("{}", my_str); my_closure(); //可多次调用 my_closure(); // String没有实现copy,因此是Fn // FnMut方式 let mut my_str = String::form("string"); let mut my_closure = || { my_str.push_str(" clone"); println!("{}", my_str); } my_closure(); //可多次调用,my_str会新增clone字符串 my_closure(); // 如果改变my_str, 就变成了FnMut // FnOnce方式 let my_vec: Vec<i32> = vec![8, 9, 10]; let my_closure = || { my_vec .into_iter() // into_iter takes ownership .map(|x| x as u8) // turn it into u8 .map(|x| x * 2) // multiply by 2 .collect::<Vec<u8>>() // collect into a Vec }; let new_vec = my_closure(); //只能使用一次