当前位置: 首页 > news >正文

承德市建设局网站品牌建设口号

承德市建设局网站,品牌建设口号,wordpress万网,桂阳网页定制文章目录 一、pattern matching二、trait2.1 常见 trait2.1.1 Copy 和 Clone2.1.2 PartialEq 和 Eq2.1.3 PartialOrd 和 Ord2.1.4 Hash2.1.5 From, Into, TryFrom, TryInto 2.2 概念2.2.1 关联类型2.2.2 关联常量2.3.3 泛型关联类型2.3.3.1 示例: 用泛型关联类型, 创建集合工厂… 文章目录 一、pattern matching二、trait2.1 常见 trait2.1.1 Copy 和 Clone2.1.2 PartialEq 和 Eq2.1.3 PartialOrd 和 Ord2.1.4 Hash2.1.5 From, Into, TryFrom, TryInto 2.2 概念2.2.1 关联类型2.2.2 关联常量2.3.3 泛型关联类型2.3.3.1 示例: 用泛型关联类型, 创建集合工厂2.3.3.2 在函数式编程中使用泛型关联类型 三 生命周期3.1 子类型3.2 高阶生命周期绑定(HRTB): 泛型的泛型 四 闭包4.1 move 关键字: 强制捕获上下文的所有权4.2 闭包的类型推断4.3 闭包的 trait 的表示和存储4.2.1 示例: 将闭包作为函数参数或返回值4.2.2 示例: 将闭包存储到数据结构中 五 迭代器5.1 示例: 消耗迭代器进行遍历的基本方法5.2 迭代器的 trait5.2.1 示例: 使用 trait 方法消耗迭代器5.2.2 示例: 自定义计数器迭代器5.3.3 展开 for 循环 5.4 迭代器的变换和消耗5.4.1 示例: 变换和消耗5.4.2 迭代器的性能 六 智能指针6.1 智能指针的特征6.2 智能指针的引用计数RC6.3 内部可变性6.3.1 RefCell6.3.3.1 示例: 上例使用 RefCell 的效果6.3.3.2 示例: 使用 Rc RefCell 实现双向链表 七 并发与并行7.1 进程和线程7.2 多线程数据访问: 消息传递7.3 多线程数据访问: 状态共享7.4 多线程相关 trait: Send 和 Sync7.4.1 使用 Arc 智能指针 八 unsafe Rust8.1 裸指针 *const T 和 *mut T8.2 ManuallyDropT8.3 NonNullT8.4 MaybeUninitT8.5 其他函数和方法 本地运行 rustup doc 即可打开 rust 官方文档 一、pattern matching 模式匹配 let a 0;match a {0 println!(zero),_ println!(non-zero),}// let 就是一种 pattern match 的表达式 #[warn(unused_variables)] fn main() {struct A {x: i32,y: static str,z: B,}#[derive(Debug)]enum B {X(i32),Y { a: u8, b: u8 },Z,}let a A {x: 0,y: hello,z: B::Y { a: 2, b: 3 },};let A { x, y, z } a; // 模式匹配(即对 struct 的解构), xyz 都是新的变量, 将 a 赋值给他们(PS: 因为 struct A 中的属性为 xyz, 所以必须命名为 xyz)println!({}, {}, {:?}, x, y, z); }// code result: 0, hello, Y { a: 2, b: 3 }// if let 的 pattern matching 匹配度更高 if let A {z: B::Y { a, b }, .. // ..表示忽略其他字段 } a {}if let (x, y, 3) (10, 11, 12) {} // 若 3 ! 12 则直接返回模式匹配let a 12; let s match a {90..100 A, // .. 会自动转换为 std::ops::RangeInclusive 结构体80..89 B,70..89 C,_ D, }; // ..end 会自动转换为 core::ops::RangeTo, 即 x end // start.. 会自动转换为 core::ops::RangeFrom, 即 x end二、trait 2.1 常见 trait 2.1.1 Copy 和 Clone trait core::clone::Clone 是一个对象, 其赋值对象完整的数据(当然也包括该对象的所有权) 所有不可变引用都实现了 Clone trait(因为不可变引用可以被持有多份, 所以可以被 Clone) Clone is a supertrait of Copy, so everything which is Copy must also implement Clone. If a type is Copy then its Clone implementation only needs to return *self (see the example above). We can derive a Copy implementation. Clone is also required, as it’s a supertrait of Copy. 因为实现了 Copy 和 Clone, 所以 let b a 并未转移所有权, 所以最后一行 a 仍可使用(仍在栈上), 如下图: 而若没有实现 Copy, 则会报错, 因为 let b a 所有权转移后, 无法再访问 a 了, 如下图: 而若显式调用 .clone() 即可通过编译, 如下图: 如果定义了 A.ptr 指向堆上的内存, 则只能用Clone trait 的 clone() 错误用法如下: Copy trait 会造成 a.ptr 和 b.ptr 都指向同一份堆上的内存, 造成垂悬引用, 虽然 rust 编译器不会报错, 但这是不安全的, 而应当用智能指针来解决. 如下图: 2.1.2 PartialEq 和 Eq Eq implies PartialEq 区别 PartialEq 描述的是部分相等关系(离散数学的偏序关系), 如 float 中 Nan 和 Nan 是无法比较的, 所以 float 是 PartialEq Eq 描述的是完全相等关系(离散数学的全序关系) 只要实现了 PartialEq, 就可用 a b 和 a ! b 来表达 PartialEq 是离线数学的偏序关系, 若 a b, 且 b c, 无法推导出 a c Eq 是离线数学的全序关系, 若 a b, 且 b c, 能推导出 a c 如果想表达部分相等关系, 则只实现 PartialEq 即可 如果想表达完全相等关系, 则实现 PartialEq 后, 再用 impl Eq for Book {} 实现默认的 Eq 方法即可 #[warn(dead_code)] fn main() {enum BookFormat {Paperback,Hardback,Ebook,}struct Book {isbn: i32,format: BookFormat,}impl PartialEq for Book {fn eq(self, other: Self) - bool {self.isbn other.isbn}}impl Eq for Book {}let a Book {isbn: 1,format: BookFormat::Paperback,};let b Book {isbn: 1,format: BookFormat::Hardback,};assert!(a b) }fn main() {let f1 3.14;let f2 3.15;if f1 f2 {println!(same);}if f1 ! f2 {println!(not same);}is_eq(f1); // 编译不通过, 因为 float 仅实现了 PartialEq, 而因为 Nan 无法比较故未实现 Eqis_partial_eq(f1); }fn is_eqT: Eq(f: T) {} fn is_partial_eqT: PartialEq(f: T) {}不同类型也可各自实现 PartialEq, 从而比较 type1 type2, 但是传递性会有问题, 如下例: #[derive(PartialEq)] enum BookFormat {Paperback,Hardback,Ebook, }#[derive(PartialEq)] struct Book {isbn: i32,format: BookFormat, }impl PartialEqBookFormat for Book {fn eq(self, other: BookFormat) - bool {self.format *other} }impl PartialEqBook for BookFormat {fn eq(self, other: Book) - bool {*self other.format} }fn main() {let b1 Book { isbn: 1, format: BookFormat::Paperback };let b2 Book { isbn: 2, format: BookFormat::Paperback };assert!(b1 BookFormat::Paperback);assert!(BookFormat::Paperback b2);// The following should hold by transitivity but doesnt.assert!(b1 b2); // -- PANICS }2.1.3 PartialOrd 和 Ord PartialOrd 是离线数学的偏序关系, 若 a b, 且 b c, 无法推导出 a c Ord 是离线数学的全序关系, 若 a b, 且 b c, 能推导出 a c 2.1.4 Hash #[derive(Hash)] struct Rustacean {name: String,country: String, }也可以自定义用某些字段做 Hash, 示例如下: use std::hash::{Hash, Hasher};struct Person {id: u32,name: String,phone: u64, }impl Hash for Person {fn hashH: Hasher(self, state: mut H) {self.id.hash(state);self.phone.hash(state);} }2.1.5 From, Into, TryFrom, TryInto TryFrom 定义了错误处理: pub trait TryFromT: Sized {type Error;// Required methodfn try_from(value: T) - ResultSelf, Self::Error; }struct GreaterThanZero(i32);impl TryFromi32 for GreaterThanZero {type Error static str;fn try_from(value: i32) - ResultSelf, Self::Error {if value 0 {Err(GreaterThanZero only accepts values greater than zero!)} else {Ok(GreaterThanZero(value))}} }let big_number 1_000_000_000_000i64; // Silently truncates big_number, requires detecting // and handling the truncation after the fact. let smaller_number big_number as i32; assert_eq!(smaller_number, -727379968);// Returns an error because big_number is too big to // fit in an i32. let try_smaller_number i32::try_from(big_number); assert!(try_smaller_number.is_err());// Returns Ok(3). let try_successful_smaller_number i32::try_from(3); assert!(try_successful_smaller_number.is_ok());2.2 概念 本质: 表示一组特定的功能 包含: 方法, 关联类型, 常量 2.2.1 关联类型 例如如下自行实现的一个 函数 trait: fn main() {trait FunctionArgs {// Args: 输入参数type Output; // Output: 关联类型fn call(args: Args) - Self::Output;}struct AddFunction; // 单元结构体, 其内存布局相当于()// 两个数的加法, 入参为(T, T), 关联类型为 Output TimplT: std::ops::AddOutput T Function(T, T) for AddFunction {type Output T;fn call(args: (T, T)) - Self::Output {args.0 args.1}}// 三个数的加法, 入参为(T, T), 关联类型为 Output TimplT: std::ops::AddOutput T Function(T, T, T) for AddFunction {type Output T;fn call(args: (T, T, T)) - Self::Output {args.0 args.1 args.2}}// 虽两种 AddFunction 的泛型实现, 但关联类型 Output 只有一种assert_eq!(AddFunction::call((1, 2)), 3);assert_eq!(AddFunction::call((1, 2, 3)), 6); }2.2.2 关联常量 // 下文抽象了寄存器访问内存地址 use std::marker::PhantomData;fn main() {//------如下为定义------enum Access {Read,Write,ReadWrite,}trait MmioReg {const OFFSET: usize; // 关联常量const ACCESS: Access; // 关联常量type Repr: Sized Copy; // 关联类型 Repr 意为寄存器fn at(base: std::ptr::NonNull()) - VolatileSelf::Repr {let _address base.as_ptr() as usize Self::OFFSET;Volatile(Self::ACCESS, PhantomData)}}struct VolatileT(Access, std::marker::PhantomDataT); // struct, 标识用什么方式(Access), 读写一个内存指针(PhantomData)//------如下为使用------struct SampleReg;impl MmioReg for SampleReg {const OFFSET: usize 0x100;const ACCESS: Access Access::ReadWrite;type Repr u32;}let reg SampleReg::at(std::ptr::NonNull::dangling()); }2.3.3 泛型关联类型 trait 内的关联类型, 本身也可以是泛型的 2.3.3.1 示例: 用泛型关联类型, 创建集合工厂 fn main() {// -------定义trait如下trait CollectionFactory {type CollectionT;type Itera, TwhereT: a;fn emptyT() - Self::CollectionT;fn itera, T(collection: a Self::CollectionT) - Self::Itera, TwhereT: a;}// -------实现trait如下struct VecFactory;impl CollectionFactory for VecFactory {type CollectionT VecT;type Itera, T std::slice::Itera, T where T: a;fn emptyT() - Self::CollectionT {Vec::new()}fn itera, T(collection: a Self::CollectionT) - Self::Itera, TwhereT: a,{collection.iter()}}// ------使用如下, 传入 T 和 CollectionFactorystruct QueueT, F: CollectionFactory {inner: F::CollectionT,}let vec_based_queue Queue::_, VecFactory {inner: vec![1, 2, 3],}; }2.3.3.2 在函数式编程中使用泛型关联类型 fn main() {trait FunctorT {type OutputU: FunctorU;fn fmapU(self, f: impl FnOnce(T) - U) - Self::OutputU;}implT FunctorT for OptionT {type OutputU OptionU;fn fmapU(self, f: impl FnOnce(T) - U) - Self::OutputU {self.map(f)}}let s Some(1);let s s.fmap(|x| x 1);assert_eq!(s, Some(2)); }三 生命周期 本质: 一个结构单元, 其包括了一个变量/类型的存活范围 fn main() {fn longesta(x: a str, y: a str) - a str {if x.len() y.len() {x} else {y}}let l longest(a, abc);assert_eq!(l, abc); }fn main() {struct Refa, T(a T);let x 42;let y Ref(x);assert_eq!(y.0, 42); }3.1 子类型 生命周期的包含关系: 比 … 活得久(outlive) 结论: a: b 等价于 a 比 b 活得久, 即 a outlives b定理: 对于任意生命周期 a, 有 static: a (即 staitc 生命周期 比 a 生命周期 活的更久) 子类型: 可替换性 定义: x 是 y 的子类型 大前提: 对于某处 “不可变引用”, 有对于单个生命周期的要求小前提: 若 y 满足该要求结论: x 也满足该要求 暴论: 类型越子, 可以满足的要求越多 结合以上两组结论, 我们有 a: b 等价于 a 是 b 的子类型 将 a 是 b 的子类型 表示为 偏序关系 , a 与 b 无关 表示为 a b, 则对于任意两个生命周期 a 和 b, 仅存在 3 种不等关系, 将这3种关系统称为 R(a, b): a b, 即 a 是 b 的子类型a b, 即 a 与 b 无关a b, 即 b 是 a 的子类型 则 R 对于泛型的映射 对于单生命周期的泛型 T, 这个映射即定义为 T: R(a, b) -- Ra, Tb), 这个关系有三种: 相同: 即若 a 是 b 的子类型, 则 Ta 是 Tb 的子类型相反: 即若 a 是 b 的子类型, 则 Tb 是 Ta 的子类型无关: 即若 a 是 b 的子类型, 则 Ta 和 Tb 无关 示例如下: fn main() {struct Aa(a i32); // A即为一个单生命周期的类型构造器let x 1;// 外括号的生命周期为a{let y: i32 x;// 内括号的生命周期为b{let z: i32 x;}}// 因为外括号的存活域比内括号的存活域大, 设外括号的生命周期为a, 设内括号的生命周期为b// 则 a 是 b 的子类型// 则对于实际构造出的两个引用(y 和 z), 即有 y 是生命周期为a 的 i32, z 是生命周期为b 的 i32 }更详细的解释是: fn main() {struct Aa(a i32); // A即为一个单生命周期的类型构造器let x 1;// 外括号的生命周期为a{let mut y: i32 x;// 内括号的生命周期为b{let mut z: i32 x;y z; // 可编译通过z y; // 可编译通过}}// 因为外括号的存活域比内括号的存活域大, 设外括号的生命周期为a, 设内括号的生命周期为b// 则 a 是 b 的子类型// 则对于实际构造出的两个引用(y 和 z), 即有 y 是生命周期为a 的 i32, z 是生命周期为b 的 i32// 则 y 的生命周期为 a, z 的生命周期为 b// 则生命周期为 b 的 i32, 可以被 生命周期为 a 的 i32 替换// 生命周期为 a 的 i32, 就是生命周期为 b 的 i32 (子类型 a 就是父类型 b)// 构成了一种映射: 若 a 是 b 的子类型, 则 a i32 是 b i32 的子类型 }总结三种映射关系如下: 不可变引用, 是协变关系 (示例如上) 如 static str 是 str 的子类型, 即 static str 可替换 str 函数, 是逆变关系 如 fn(static str) 并不是 fn(x str) 的子类型, 即不能用 fn(static str) 替换 fn(x str).但反而 fn(x str) 是 fn(static str) 的子类型, 即能用 fn(x str) 替换 fn(static str) 可变引用, 是不变关系 示例: 如下图即为悬垂引用的示例 用传统 rust 话术是这样解释的: 因为 hello 是 static 生命周期, 而 world 只有 x 的生命周期, 所以 当将 hello 指向 world 的引用时, rust 编译器会报错: world does not live long enough, 即当 world 走出其作用域而失效时, 会造成 hello 指向悬垂引用: 另一种解释话术如下: 详见 file:///Users/y/.rustup/toolchains/stable-aarch64-apple-darwin/share/doc/rust/html/nomicon/subtyping.html?highlightsubtyping#subtyping 3.2 高阶生命周期绑定(HRTB): 泛型的泛型 四 闭包 本质: 拥有可能的关联上下文的匿名函数结构体 fn main() {let x 5;let plus_x |a| a x;assert_eq!(plus_x(5), 10); }闭包实际展开如下: #[test] fn expansion() {struct Anonymousa(a i32);impla Anonymousa {// 捕获fn new(x: a i32) - Self {Anonymous(x)}// 使用fn call(self, a: i32) - i32 {a self.0}}let x 5;let plus_x Anonymous::new(x);assert_eq!(plus_x.call(5), 10); }4.1 move 关键字: 强制捕获上下文的所有权 不使用 move 时如下: #[test] fn use_keyword_move() {let vec vec![1, 2, 3];{let print_borrowed_vec || println!({vec:?}); // 不使用 move 关键字时, 闭包是以引用方式捕获的println!({vec:?});print_borrowed_vec()} }使用 move 时如下: #[test] fn use_keyword_move() {let vec vec![1, 2, 3];{let print_owned_vec move || println!({vec:?});println!({vec:?}); // 编译报错, 因vec 的所有权已在上一行被转移了print_owned_vec();} }move 其实是一个语法糖, 我们也可自己捕获, 如下例是等价的两个闭包: fn use_keyword_move() {let vec vec![1, 2, 3];// {// let print_owned_vec move || println!({vec:?});// print_owned_vec();// }{let print_owned_vec || {let vec vec; // vec 捕获了所有权println!({vec:?});};print_owned_vec();} }4.2 闭包的类型推断 4.3 闭包的 trait 的表示和存储 // FnOnce 示例如下: let print_owned_vec move || println!({vec:?}); // 是FnOnce, 即调用一次就会消耗其所有权// FnMut 示例如下:struct Anonymousa(a mut i32); // 是 mut, 所以每调用一次都会使其上下文发生改变, 则它只实现了 FnMut, 而没有实现 Fnimpla Anonymousa {// 捕获fn new(x: a i32) - Self {Anonymous(x)}// 使用fn call(self, a: i32) - i32 {a self.0}}// Fn 示例如下: let plus_x |a| a x; // 是Fn, 因为获取的都是不可变引用, 所以其可被无损的调用任意次他们之间是包含关系: 只要实现了 Fn, 则一定也实现了 FnMut 和 FnOnce只要实现了 FnMut, 则一定也实现了 FnOnce 4.2.1 示例: 将闭包作为函数参数或返回值 #[test] fn pass_as_parameters_and_return_values() {fn plus(x: i32) - impl Fn(i32) - i32 {move |a| a x}fn mapT, U(value: T, f: impl FnOnce(T) - U) - U {f(value)}fn assert_fn_onceF: FnOnce(i32) - i32(_: F) {}fn assert_fn_mutF: FnMut(i32) - i32(_: F) {}let x 5;let plus_x plus(x); // 因为 plus_x 实现了 Fn, 又因为若实现了 Fn 则一定也实现了 FnMut 和 FnOnceassert_fn_once(plus_x); // 所以 plus_x 实现了 FnOnce, 所以此断言通过assert_fn_mut(plus_x);assert_eq!(map(2, plus_x), 7); }4.2.2 示例: 将闭包存储到数据结构中 #[test] fn storage() {// -----定义:struct ServiceBuilderOpener {params: OptionString,opener: Opener,}implOpener ServiceBuilderOpener {fn new(opener: Opener) - Self {Self {params: None,opener,}}fn with_params(mut self, params: String) - Self {self.params Some(params);self}}implService, Opener: FnOnce(String) - Service ServiceBuilderOpener {fn open(self) - Service {let params self.params.expect(Please input some params);(self.opener)(params)}}// -----使用:let opener |params| {println!(Opening service with params: {params});mocked service};let init_service ServiceBuilder::new(opener).with_params(Some params.to_string());let service init_service.open();println!(Service is {service:?}); }// output result as belows: Opening service with params: Some params Service is mocked service test storage ... ok五 迭代器 本质: 对序列的流失处理–变换或消耗 5.1 示例: 消耗迭代器进行遍历的基本方法 #[test] fn basic_usage() {let array [1, 2, 3, 4, 5];let iter array.iter();for item in iter {println!({item});} }5.2 迭代器的 trait 5.2.1 示例: 使用 trait 方法消耗迭代器 #[test] fn iterator_traits() {let array [1, 2, 3, 4, 5];let mut iter array.iter();assert_eq!(iter.next(), Some(1));assert_eq!(iter.next(), Some(2));assert_eq!(iter.next(), Some(3));assert_eq!(iter.next(), Some(4));assert_eq!(iter.next(), Some(5));assert_eq!(iter.next(), None);assert_eq!(iter.next(), None); }5.2.2 示例: 自定义计数器迭代器 #[test] fn custom_iterator() {struct Counter {start: i32,count: i32,}impl Iterator for Counter {type Item i32;fn next(mut self) - OptionSelf::Item {if self.count 0 {let ret self.start;self.start 1;self.count - 1;Some(ret)} else {None}}}let mut counter Counter { start: 3, count: 5 };for item in counter {println!({item},);} }// code result: 3 4 5 6 75.3.3 展开 for 循环 #[test] fn expand_for_loop() {let array [1, 2, 3, 4, 5];for item in array.iter() {println!({item});}// 可展开为 while let{let mut iter array.iter();while let Some(item) iter.next() {println!({item});}}// 也可展开为 loop matchlet mut iter array.iter();loop {match iter.next() {Some(item) println!({item}),None break,}} }5.4 迭代器的变换和消耗 迭代器是 rust 函数式编程经常使用的场合 5.4.1 示例: 变换和消耗 fn main() {struct Person {name: String,age: i32,}let people [Person {name: Alice.to_string(),age: 21,},Person {name: Bob.to_string(),age: 25,},Person {name: Charlie.to_string(),age: 18,},Person {name: Dave.to_string(),age: 30,},Person {name: Eve.to_string(),age: 28,},Person {name: Frank.to_string(),age: 32,},];let student_ids [1001, 1002, 1003, 1004, 1005, 1006];let all_names people.iter().map(|p| p.name.clone()).collect::Vec_();println!({:?}, all_names);// let first_3_student_ids_whose_age_is_over_21let mut first_3_student_ids_whose_age_is_over_21 Vec::new();for index in 0..6 {let person people[index];let id student_ids[index];if person.age 21 {first_3_student_ids_whose_age_is_over_21.push(id);if first_3_student_ids_whose_age_is_over_21.len() 3 {break;}}}assert_eq!(first_3_student_ids_whose_age_is_over_21, [1002, 1004, 1005]);let first_3_student_ids_whose_age_is_over_21 people.iter().zip(student_ids.iter())//.filter(|(p, _)| p.age 21)//.map(|(_, id)| *id)..filter_map(|(p, id)| (p.age 21).then_some(id)).take(3).collect::Vec_();assert_eq!(first_3_student_ids_whose_age_is_over_21, [1002, 1004, 1005]); }5.4.2 迭代器的性能 迭代器性能很好, 程序员不需要为了性能而使用 for, 使用 迭代器即可兼顾性能和可读性 六 智能指针 fn main() {} #[test] fn basic_usage() {let x 5;let boxed_x Box::new(x); // Box将无法在编译期确定大小的东西, 变为可在编译器确定大小let y *boxed_x; // 解引用let z *boxed_x;assert_eq!(y, z); }Box use std::collections::HashMap; fn main() {} #[test] fn basic_usage() {let x 5;let boxed_x Box::new(x);let y *boxed_x;let z *boxed_x;assert_eq!(y, z);let array [1, 2, 3, 4, 5];let mut iter Box::new(array.into_iter()) as Boxdyn IteratorItem i32;let hash_map [(1, ()), (2, ())].into_iter().collect::HashMap_, _();iter Box::new(hash_map.into_keys()); }vec fn main() {} #[test] fn basic_usage() {let x 5;let boxed_x Box::new(x);let y *boxed_x;let z *boxed_x;assert_eq!(y, z);let array [1, 2, 3, 4, 5];let slice array[1..3];let vec slice.to_vec();let vec_slice vec[..];assert_eq!(vec_slice, slice); }String fn main() {} #[test] fn basic_usage() {let x 5;let boxed_x Box::new(x);let y *boxed_x;let z *boxed_x;assert_eq!(y, z);let s Hello world;let s_slice s[1..3];let string s.to_string();let string_slice string[1..3];assert_eq!(string_slice, s_slice); }6.1 智能指针的特征 源码中 String 的 Deref 实现如下: 自己实现的 智能指针 Smart 如下, 主要是实现了 Deref trait: use std::ops::Deref;fn main() {}#[test] fn custom_smart_pointers() {struct SmartT(T);implT SmartT {fn new(value: T) - Self {Self(value)}}implT Deref for SmartT {type Target T;fn deref(self) - Self::Target {self.0}}let smart Smart::new(5);assert_eq!(*smart, 5) }自己实现的 智能指针 Smart 如下, 除了实现 Deref trait, 还实现了 DerefMut trait: use std::ops::{Deref, DerefMut};fn main() {}#[test] fn custom_smart_pointers() {struct SmartT(T);implT SmartT {fn new(value: T) - Self {Self(value)}}implT Deref for SmartT {type Target T;fn deref(self) - Self::Target {self.0}}implT DerefMut for SmartT {fn deref_mut(mut self) - mut Self::Target {mut self.0}}let mut smart Smart::new(5);assert_eq!(*smart, 5);*smart 10;assert_eq!(*smart, 10); }6.2 智能指针的引用计数RC use std::rc::Rc;fn main() {let c Node::new(1, None);let b Node::new(2, Some(Rc::clone(c)));let a Node::new(3, Some(Rc::clone(b)));let x Node::new(4, Some(Rc::clone(a)));let y Node::new(5, Some(Rc::clone(a)));// 因为 x 和 y 都共享 a, 所以有两条链表, 分别是 xabc 和 yabclet vec_x x.to_vec();assert_eq!(vec_x, vec![4, 3, 2, 1]);let vec_y y.to_vec_iterated();assert_eq!(vec_y, vec![5, 3, 2, 1]); }struct NodeT {data: T,next: OptionRcNodeT, }implT NodeT {fn new(data: T, next: OptionRcNodeT) - RcSelf {Rc::new(Node { data, next })}fn to_vec(self: RcSelf) - VecTwhereT: Clone,{let mut vec Vec::new();let mut node Some(Rc::clone(self));while let Some(n) node {vec.push(n.data.clone());node n.next.as_ref().map(Rc::clone);}vec}// -----使用迭代器如下:fn to_vec_iterated(self: RcSelf) - VecTwhereT: Clone,{let mut node Some(Rc::clone(self));let iter std::iter::from_fn(move || match node.take() {Some(n) {node n.next.as_ref().map(Rc::clone);Some(n.data.clone())}None None,});iter.collect()} }6.3 内部可变性 fn main() {}#[test] fn interior_mutability() {#![allow(unused)]trait MessageSender {fn send(self, message: String); // self 是不可变引用}struct ValidatorM: MessageSender(M);implM: MessageSender ValidatorM {fn validate(self, value: i32) {if !(-10..10).contains(value) {self.0.send(format!(Value {} is not in range [-10, 10], value));}}}struct MockMessageSender {messages: VecString,}impl MessageSender for MockMessageSender {fn send(self, message: String) {self.messages.push(message); // 因为需要调用 push(), 所以需要 self 内部的 messages 是可变的, 而 self 本身是不可变引用, 所以需要内部可变性}} }6.3.1 RefCell 本质是先在编译期通过, 但运行时如果发生错误仍会直接 panic(), 所以非常坏的一种实践 6.3.3.1 示例: 上例使用 RefCell 的效果 6.3.3.2 示例: 使用 Rc RefCell 实现双向链表 七 并发与并行 7.1 进程和线程 示例: 使用 std::thread 创建线程, 使用 JoinHandle() 等待线程完成 use std::thread;fn main() {}#[test] fn use_multithread() {let thread thread::spawn(|| {for i in 0..10 {println!(thread: {}, i);}});for i in 0..10 {println!(main: {}, i);}thread.join().unwrap(); }// code result: main: 0 main: 1 main: 2 main: 3 main: 4 main: 5 main: 6 main: 7 main: 8 main: 9 thread: 0 thread: 1 thread: 2 thread: 3 thread: 4 thread: 5 thread: 6 thread: 7 thread: 8示例: 使用 move 在多线程间用闭包捕获所有权 use std::thread;fn main() {}#[test] fn move_between_threads() {let vec vec![1, 2, 3, 4, 5];let thread thread::spawn(move || {let mut vec vec;vec.push(6);println!({vec:?});});// println!({vec:?}); // 此处无法再使用 vec, 因为其所有权已被 move 到线程里了thread.join().unwrap(); }// code result: [1, 2, 3, 4, 5, 6]7.2 多线程数据访问: 消息传递 uuse std::{sync::mpsc, thread};fn main() {}#[test] fn mpsc_channels() {let (tx, rx) mpsc::channel();for t in 0..10 {let tx tx.clone();thread::spawn(move || {for i in 0..3 {let num 100 * t i;tx.send(num).unwrap();}});}drop(tx); // drop main()函数中的 tx// 当所有发送端都发送完毕后, 则 mpsc 的所有 rx 都会自动 drop, 则rx.recv() 会返回 Errwhile let Ok(num) rx.recv() {println!({}, num);} }7.3 多线程数据访问: 状态共享 use std::{sync::{mpsc, Mutex},thread,time::Duration, };fn main() {}#[test] fn mutexes() {static DATA: Mutexi32 Mutex::new(0);thread::spawn(|| {for i in 0..10 {*DATA.lock().unwrap() i;thread::sleep(Duration::from_secs(1));}});while *DATA.lock().unwrap() 45 {println!(Waiting);thread::sleep(Duration::from_secs(1));} }// code result: 打印 10 次 Waiting 后值大于 45, 故退出 main() 函数 running 1 test Waiting Waiting Waiting Waiting Waiting Waiting Waiting Waiting Waiting Waiting test mutexes ... ok7.4 多线程相关 trait: Send 和 Sync 7.4.1 使用 Arc 智能指针 Arc 即 Atomic 的 Rc, 可在线程间使用 use std::{sync::{mpsc, Mutex, Arc},thread,time::Duration, };fn main() {}#[test] fn arc_usage() {let data Arc::new(Mutex::new(0));let d2 data.clone();thread::spawn(move || {for i in 0..10 {*d2.lock().unwrap() i;thread::sleep(Duration::from_secs(1));}});while *data.lock().unwrap() 45 {println!(Waiting);thread::sleep(Duration::from_secs(1));} }Arc 源码如下: 八 unsafe Rust unsafe 块一定要写注释, 示例如下: 8.1 裸指针 *const T 和 *mut T 8.2 ManuallyDrop 8.3 NonNull 8.4 MaybeUninit 8.5 其他函数和方法
http://www.tj-hxxt.cn/news/229280.html

相关文章:

  • 佛山响应式网站公司厦门seo结算
  • 沧州工商联网站建设省内新闻最新消息
  • 公司做网站留言板创新网站建设工作
  • 什么网站做电子相册比加快电商seo搜索引擎优化
  • 县区网站服务器机房建设网站开发后服务费
  • 莱西网站建设哪家好旅游网站首页设计模板
  • 网站解析后 问题开创云网站建设支持
  • 简历制作网站哪个好网站建设计划书1200字
  • 河南网站建设公司哪个好呀wordpress 显示标签
  • 临沂网站设计公司网站优化 前端怎么做
  • 淄博网站建设电话咨询网站 三合一
  • 成都建设网站哪些公司好wordpress图片清晰度
  • 开了网站建设公司 如何接业务百度网站权重查询
  • 网站建设哪里招标wordpress 更改模板路径
  • 交换机可以做网站跳转吗网站建设需要很强的编程
  • 长春网站设计制作培训周口网站推广
  • 福州专业网站建设价格如何免费注册个人邮箱
  • 网站建设时间怎么查询能不能把wordpress程序转到帝国
  • 网站建设服务杭州好的app设计网站
  • 上海seo网站优化一个域名访问不同的网站
  • 潮州网站制作苏州做网版的公司
  • 杨陵区住房和城乡建设局网站网站项目宣传片
  • 广州专业的网站制作淘宝客网站域名备案吗
  • html中文美食网站照片合成制作app
  • 网站推广怎么做比较好网站维护基础知识
  • 黑白灰网站网站设计网站优化公司
  • 网站运营方案ppt音乐如何到wordpress
  • 做购物网站有什么要求吗做网站的为什么那么多骗子
  • 买域名之后怎样做网站南京网站费用网站建设
  • 怎么做企业网站平台苏州vr全景网站建设公司