Rust从入门到劝退 ( 二 )
RUST 进阶
基本上是跟着B站上进行学习,代码和笔记也是跟着视频学习的,Rust确实和C++系十分类似,同样现在C++的一些用法和Rust也有一定的共同性,但是Rust在安全、堆栈、强制转换等方面确实要求很高
-
泛型
//1、泛型是具体类型或者其它属性的抽象替代,用于减少代码重复. //2、在函数定义中使用泛型。 //3、在结构体中使用泛型。 //4、枚举中的泛型。 //5、方法中的泛型。 //6、总结:使用泛型并不会造成程序性能上的损失。rust通过在编译时进行泛型代码的单态化来保证效率。单态化时通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程。 ////--------没有泛型----------- ////for i32 //fn largest_i32(list: &[i32]) -> i32 { // let mut largest = list[0]; // for &item in list.iter() { // if item > largest { // largest = item; // } // } // // largest //} // ////for char //fn largest_char(list: &[char]) -> char { // let mut largest = list[0]; // for &item in list.iter() { // if item > largest { // largest = item; // } // } // // largest //} ////----------使用泛型------------- //fn largest<T: PartialOrd + Copy> (list: &[T]) -> T { // let mut larger = list[0]; // for &item in list.iter() { // if item > larger { // larger = item; // } // } // larger //} // //fn main() { // let number_list = vec![1, 2, 23, 34, 8, 100]; // //let max_number = largest_i32(&number_list); // let max_number = largest(&number_list); // println!("max_number = {}", max_number); // // let char_list= vec!['a', 'y', 'b']; // //let max_char = largest_char(&char_list); // let max_char = largest(&char_list); // println!("max_char = {}", max_char); // println!("Hello, world!"); //} ////------在结构体中使用泛型-------- //#[derive(Debug)] //struct Point<T> { // x: T, // y: T, //} // //#[derive(Debug)] //struct Point2<T, U> { // x: T, // y: U, //} // //fn main() { // let integer = Point{x: 1, y: 2}; // println!("{:#?}", integer); // // let float = Point{x: 1.1, y: 2.2}; // println!("{:?}", float); // // let a = Point2{x: 1.1, y: 'a'}; // println!("a = {:?}", a); //} // ////----------在枚举中使用泛型------------ //enum Option<T> { // Some(T), // None, //} // //enum Result<T, E> { // Ok(T), // Err(E) //} ////---------------------------------------- //-----------在方法中使用泛型-------------- struct Point<T> { x: T, y: T, } impl<T> Point<T> { fn get_x(&self) -> &T { &self.x } fn get_y(&self) -> &T { &self.y } } struct Point2<T, U> { x: T, y: U, } impl<T, U> Point2<T, U> { fn creat_point<V, W>(self, other: Point2<V, W>) -> Point2<T, W> { Point2 { x: self.x, y: other.y, } } } fn main() { let p = Point{x:1, y: 2}; println!("x = {}", p.get_x()); println!("y = {}", p.get_y()); let p = Point{x:1.1, y: 2.2}; println!("x = {}", p.get_x()); println!("y = {}", p.get_y()); let p1 = Point2{x: 5, y: 1.1}; let p2 = Point2{x: "hello", y: 'c'}; let p3 = p1.creat_point(p2); println!("p3.x = {}, p3.y = {}", p3.x, p3.y); } -
trait
//1、trait用于定义与其它类型共享的功能,类似于其它语言中的接口。 //(1)可以通过trait以抽象的方式定义共享的行为。 //(2)可以使用trait bounds指定泛型是任何拥有特定行为的类型。 //2、定义trait pub trait GetInformation { fn get_name(&self) -> &String; fn get_age(&self) -> u32; } trait SchoolName { fn get_school_name(&self) -> String { String::from("HongXingSchool") } } //3、实现trait pub struct Student { pub name: String, pub age: u32, } impl SchoolName for Student {} impl GetInformation for Student { fn get_name(&self) -> &String { &self.name } �------------ //enum Option<T> { // Some(T), // None, //} // //enum Result<T, E> { // Ok(T), // Err(E) //} ////---------------------------------------- //-----------在方法中使用泛型-------------- struct Point<T> { x: T, y: T, } impl<T> Point<T> { fn get_x(&self) -> &T { &self.x } fn get_y(&self) -> &T { &self.y } } struct Point2<T, U> { x: T, y: U, } impl<T, U> Point2<T, U> { fn creat_point<V, W>(self, other: Point2<V, W>) -> Point2<T, W> { Point2 { x: self.x, y: other.y, } } } fn main() { let p = Point{x:1, y: 2}; println!("x = {}", p.get_x()); println!("y = {}", p.get_y()); let p = Point{x:1.1, y: 2.2}; println!("x = {}", p.get_x()); println!("y = {}", p.get_y()); let p1 = Point2{x: 5, y: 1.1}; let p2 = Point2{x: "hello", y: 'c'}; let p3 = p1.creat_point(p2); println!("p3.x = {}, p3.y = {}", p3.x, p3.y); } -
trait
//1、trait用于定义与其它类型共享的功能,类似于其它语言中的接口。 //(1)可以通过trait以抽象的方式定义共享的行为。 //(2)可以使用trait bounds指定泛型是任何拥有特定行为的类型。 //2、定义trait pub trait GetInformation { fn get_name(&self) -> &String; fn get_age(&self) -> u32; } trait SchoolName { fn get_school_name(&self) -> String { String::from("HongXingSchool") } } //3、实现trait pub struct Student { pub name: String, pub age: u32, } impl SchoolName for Student {} impl GetInformation for Student { fn get_name(&self) -> &String { &self.name } �------------ //enum Option<T> { // Some(T), // None, //} // //enum Result<T, E> { // Ok(T), // Err(E) //} ////---------------------------------------- //-----------在方法中使用泛型-------------- struct Point<T> { x: T, y: T, } impl<T> Point<T> { fn get_x(&self) -> &T { &self.x } fn get_y(&self) -> &T { &self.y } } struct Point2<T, U> { x: T, y: U, } impl<T, U> Point2<T, U> { fn creat_point<V, W>(self, other: Point2<V, W>) -> Point2<T, W> { Point2 { x: self.x, y: other.y, } } } fn main() { let p = Point{x:1, y: 2}; println!("x = {}", p.get_x()); println!("y = {}", p.get_y()); let p = Point{x:1.1, y: 2.2}; println!("x = {}", p.get_x()); println!("y = {}", p.get_y()); let p1 = Point2{x: 5, y: 1.1}; let p2 = Point2{ fn get_age(&self) -> u32; } trait SchoolName { fn get_school_name(&self) -> String { String::from("HongXingSchool") } } //3、实现trait pub struct Student { pub name: String, pub age: u32, } impl SchoolName for Student {} impl GetInformation for Student { fn get_name(&self) -> &String { &self.name } fn get_age(&self) -> u32 { self.age } } pub struct Teacher { pub name: String, pub age: u32, pub subject: String, } impl SchoolName for Teacher{ fn get_school_name(&self) -> String { String::from("GuangmingSchool") } } impl GetInformation for Teacher{ fn get_name(&self) -> &String { &self.name } fn get_age(&self) -> u32 { self.age } } //4、默认实现:可以在定义trait的时候提供默认的行为,trait的类型可以使用默认的行为。 //5、trait作为参数 fn print_information(item: impl GetInformation) { println!("name = {}", item.get_name()); println!("age = {}", item.get_age()); } fn main() { let s = Student{name: "xiaoming".to_string(), age: 10}; let t = Teacher{name: "xiaohuang".to_string(), age: 30, subject: String::from("math")}; //println!("student, name = {}, age = {}", s.get_name(), s.get_age()); //println!("teacher, name = {}, age = {}", t.get_name(), t.get_age()); let s_school_name = s.get_school_name(); println!("student school name = {}", s_school_name); let t_school_name = t.get_school_name(); println!("teacher school name = {}", t_school_name); print_information(s); print_information(t); println!("Hello, world!"); }//1、trait_bound语法 //2、指定多个trait bound //3、返回 trait的类型 //fn print_information(item: impl GetInformation) { //直接作为参数的写法 //fn print_information<T: GetInformation>(item: T){ //使用trait bound的写法 // println!("name = {}", item.get_name()); // println!("age = {}", item.get_age()); //} trait GetName { fn get_name(&self) -> &String; } trait GetAge { fn get_age(&self) -> u32; } ////写法一: //fn print_information<T: GetName+GetAge>(item: T){ //使用trait bound的写法 // println!("name = {}", item.get_name()); // println!("age = {}", item.get_age()); //} //写法二: fn print_information<T>(item: T) where T: GetName+GetAge { //使用trait bound的写法 println!("name = {}", item.get_name()); println!("age = {}", item.get_age()); } #[derive(Debug)] pub struct Student { pub name: String, pub age: u32, } impl GetName for Student { fn get_name(&self) -> &String { &self.name } } impl GetAge for Student { fn get_age(&self) -> u32 { self.age } } fn produce_item_with_age() -> impl GetAge { Student { name: String::from("xiaoming"), age: 15, } } #[derive(Debug)] pub struct Teacher{ pub name: String, pub age: u32, } impl GetAge for Teacher { fn get_age(&self) -> u32 { self.age } } //错误的用法 //fn produce_item_with_age2() -> impl GetAge { // let is = true; // // if is { // Student { // name: String::from("xiaoming"), // age: 15, // } // } else { // Teacher { // name: String::from("xiaohuang"), // age: 15, // } // } //} fn main() { let s = Student{name: "xiaoming".to_string(), age: 10}; print_information(s); let s = produce_item_with_age(); println!("Hello, world!"); }//fn largest<T: PartialOrd + Copy> (list: &[T]) -> T { fn largest<T> (list: &[T]) -> T where T: PartialOrd + Copy { let mut larger = list[0]; for &item in list.iter() { if item > larger { larger = item; } } larger } fn main() { let number_list = vec![1, 2, 23, 34, 8, 100]; //let max_number = largest_i32(&number_list); let max_number = largest(&number_list); println!("max_number = {}", max_number); let char_list= vec!['a', 'y', 'b']; //let max_char = largest_char(&char_list); let max_char = largest(&char_list); println!("max_char = {}", max_char); println!("Hello, world!"); }//使用trait bound有条件的实现方法 trait GetName { fn get_name(&self) -> &String; } trait GetAge { fn get_age(&self) -> u32; } struct PeopleMatchInformation<T, U> { master: T, student: U, } impl<T: GetName+GetAge, U: GetName+GetAge> PeopleMatchInformation<T, U> { fn print_all_information(&self) { println!("in print_all_information"); println!("master name = {}", self.master.get_name()); println!("master age = {}", self.master.get_age()); println!("student name = {}", self.student.get_name()); println!("student age = {}", self.student.get_age()); } } struct Teacher { name: String, age: u32, } impl GetName for Teacher { fn get_name(&self) -> &String { &(self.name) } } impl GetAge for Teacher { fn get_age(&self) -> u32 { self.age } } struct Student{ name: String, age: u32, } impl GetName for Student{ fn get_name(&self) -> &String { &(self.name) } } impl GetAge for Student{ fn get_age(&self) -> u32 { self.age } } fn main() { let s = Student{name: "xiaoming".to_string(), age:15}; let t = Teacher{name: "xiaohuang".to_string(), age:30}; let m = PeopleMatchInformation{master: t, student: s}; m.print_all_information(); println!("Hello, world!"); }//对任何实现了特定trait的类型有条件的实现trait trait GetName { fn get_name(&self) -> &String; } trait PrintName { fn print_name(&self); } impl<T: GetName> PrintName for T { fn print_name(&self) { println!("name = {}", self.get_name()); } } struct Student { name: String, } impl GetName for Student { fn get_name(&self) -> &String { &(self.name) } } fn main() { let s = Student{name: String::from("xiaohuang")}; s.print_name(); println!("Hello, world!"); } -
生命周期
//1、Rust中每一个引用都有其生命周期,也就是引用保持有效的作用域。大部分时候生命周期是隐含并可以推断的,正如大部分时候类型可以推断一样。 // //2、生命周期的主要目标是避免悬垂引用。 // //3、Rust编译器使用借用检查器来检查生命周期是否有效。 fn main() { ////错误例子1 //let r; //---------------------------+------------'a //{ // + // let x = 5; //-------+------'b | // r = &x; // | | //} //-------+ | //println!("r = {}", r); // | // // | //println!("Hello, world!"); // | // //---------------------------+ // let r; //---------------------------+------------'a // + let x = 5; //-------+------'b | r = &x; // | | // | | println!("r = {}", r); // | | // | | println!("Hello, world!"); // | | } //---------------------------+//函数中的生命周期 //fn longest(x: &str, y: &str) -> &str { //fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { fn longest<'c>(x: &'c str, y: &'c str) -> &'c str { if x.len() > y.len() { x } else { y } } fn get_str<'a>(x: &'a str, y: &str) -> &'a str { x } //error //fn a_str<'a>(x: &'a str, y: &'a str) -> &'a str { // let r = String::from("abc"); // r.as_str() //} fn main() { let s1 = String::from("abcde"); let s2 = String::from("ab"); let r = longest(s1.as_str(), s2.as_str()); println!("r = {}", r); let ss = get_str(s1.as_str(), s2.as_str()); //let ss2 = a_str(s1.as_str(), s2.as_str()); println!("Hello, world!"); }//1、结构体中的生命周期 #[derive(Debug)] struct A<'a> { name: &'a str, } fn main() { let n = String::from("hello"); let a = A{name: &n}; println!("a = {:#?}", a); println!("Hello, world!"); let s = get_a_str(&n); println!("s = {}", s); } //2、生命周期省略 fn get_a_str(s: &str) -> &str { s } //(1)没有生命周期注解却能够编译,原因:早期的rust中必须显式的声明生命周期,后来rust团队将很明确的模式进行了注解的简化。 //(2)遵守生命周期省略规则的情况下能明确变量的声明周期,则无需明确指定生命周期。函数或者方法的参数的生命周期称为输入生命周期,而返回值的生命周期称为输出生命周期。 //(3)编译器采用三条规则判断引用何时不需要生命周期注解,当编译器检查完这三条规则后仍然不能计算出引用的生命周期,则会停止并生成错误。 //(4)生命周期注解省略规则适用于fn定义以及impl块定义,如下: // a、每个引用的参数都有它自己的生命周期参数。例如如下: // 一个引用参数的函数,其中有一个生命周期: fn foo<'a>(x: &'a i32) // 两个引用参数的函数,则有两个生命周期 :fn foo<'a, 'b>(x: &'a i32, y: &'b i32) // 以此类推。 // b、如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数: // fn foo(x: &i32) -> &i32 等价于 fn foo<'a>(x: &'a i32) -> &'a i32 // c、如果方法有多个输入生命周期参数,不过其中之一因为方法的缘故为&self或者&mut self,那么self的生命周期被赋予所有输出生命周期参数。例子在下面来看。 // fn function(&self, x: &str, y: &str, ....) -> &str//方法中的生命周期 struct StuA<'a> { name: &'a str, } impl<'b> StuA<'b> { fn do_something(&self) -> i32 { 3 } fn do_something2(&self, s: &str) -> &str{ //fn do_something2<'b>(&'b self, s: &str) -> &'b str{ self.name } fn do_something3<'a>(&self, s: &'a str) -> &'a str{ s } } fn main() { let s = String::from("hello"); let a = StuA{name: &s}; println!("{}", a.do_something()); let s2 = String::from("hello"); println!("{}", a.do_something2(&s2)); println!("{}", a.do_something3(&s2)); println!("Hello, world!"); }//1、静态生命周期 //定义方式: 'static //其生命周期存活于整个程序期间,所有的字符字面值都拥有static生命周期。 //let s: &'static str = "hello"; // use std::fmt::Display; fn function<'a, T: Display>(x: &'a str, y: &'a str, ann: T) -> &'a str { println!("ann is {}", ann); if x.len() < y.len() { x } else { y } } fn main() { let s1 = String::from("i am s1"); let s2 = String::from("i am s2, hello"); let ann = 129; let r = function(s1.as_str(), s2.as_str(), ann); println!("r = {}", r); println!("Hello, world!"); } -
闭包
//1、闭包是可以保存进变量或者作为参数传递给其它函数的匿名函数。闭包和函数不同的是,闭包允许捕获调用者作用域中的值。 //2、闭包的使用方式 //3、使用带有泛型和Fn trait的闭包 fn main() { let use_closure = || { println!("This is a closure"); }; use_closure(); println!("Hello, world!"); //闭包定义会为每个参数和返回值类型推导一个具体的类型,但是不能推导两次 let add_one_v2 = |x: u32| -> u32 { x + 1 }; let add_one_v3 = |x| {x + 1}; let add_one_v4 = |x| x+1; let a = add_one_v1(5);//use function let b = add_one_v2(5); let c = add_one_v3(5); let d = add_one_v4(5); println!("a = {}, b = {}, c = {}, d = {}", a, b, c, d); //不能推导两次的例子 let example_closure = |x| x; let s = example_closure(String::from("hello")); println!("s = {}", s); //let n = example_closure(5); let n = example_closure(5.to_string()); println!("n = {}", n); //捕捉环境中的变量 let i = 1; let exe = |x| {x+i}; let r = exe(5); println!("r = {}", r); } //语法格式 fn add_one_v1(x: u32) -> u32 { x + 1 }//实现一个缓存,只处理第一次传入的值并保存 struct Cacher<T> where T: Fn(u32) -> u32 { calcuation: T, value: Option<u32>, } impl<T> Cacher<T> where T: Fn(u32) -> u32 { fn new(calcuation: T) -> Cacher<T> { Cacher { calcuation, value: None, } } fn value(&mut self, arg: u32) -> u32 { match self.value { Some(v) => v, None => { let v = (self.calcuation)(arg); self.value = Some(v); v }, } } } fn main() { let mut c = Cacher::new(|x| x+1); let v1 = c.value(1); println!("v1 = {}", v1); let v2 = c.value(2); println!("v2 = {}", v2); println!("Hello, world!"); }fn main() { //let x = 4; //let equal_to_x = |z| z==x; //let y = 4; //assert!(equal_to_x(y)); let x = vec![1, 2, 3]; let equal_to_x = move |z| {z==x}; println!("x === {:?}", x); let y = vec![1, 2, 3]; assert!(equal_to_x(y)); } //闭包可以通过三种方式捕获其环境,它们对应函数的三种获取参数的方式,分别是获取所有权、可变借用、不可变借用。 //这三种捕获值的方式被编码为如下三个Fn trait: //(1)FnOnce消费从周围作用域捕获的变量,闭包周围的作用域被称为其环境。为了消费捕获到的变量,闭包必须获取其所有权并在定义闭包时将其移进闭包。其名称的Once部分代表了闭包不能多次获取相同变量的所有权。 //(2)FnMut获取可变的借用值,所以可以改变其环境。 //(3)Fn从其环境获取不可变的借用值。 //当创建一个闭包时,rust会根据其如何使用环境中的变量来推断我们希望如何引用环境。由于所有闭包都可以被调用至少一次,因此所有闭包都实现了FnOnce。没有移动被捕获变量的所有权到闭包的闭包也实现了FnMut,而不需要对捕获的变量进行可变访问的闭包实现了Fn。 -
迭代器
//1、迭代器负责遍历序列中的每一项和决定序列何时结束的逻辑。 //2、创建迭代器:迭代器是惰性的,意思就是在调用方法使用迭代器之前,不会有任何效果 //3、每个迭代器都实现了iterator trait, iterator trait定义在标准库中: //trait Iterator { // type Item; // fn next(&mut self) -> Option<Self::Item>; //type Item和Self::Item这种用法叫做定义trait的关联类型 //} ////next是Iterator被要求实现的唯一的一个方法,next一次返回一个元素,当迭代器结束时候,返回None fn main() { let v1 = vec![1, 2, 3]; let mut v1_iter = v1.iter(); //到目前为止,不会对v1产生任何影响 //for val in v1_iter { // println!("val = {}", val); //} if let Some(v) = v1_iter.next() { println!("v = {}", v);//1 } if let Some(v) = v1_iter.next() { println!("v = {}", v);//2 } if let Some(v) = v1_iter.next() { println!("v = {}", v);//3 } if let Some(v) = v1_iter.next() { println!("v = {}", v); } else { println!("At end"); } //-----迭代可变引用----- let mut v2 = vec![1, 2, 3]; let mut v2_iter = v2.iter_mut(); if let Some(v) = v2_iter.next() { *v = 3; } println!("v2 = {:?}", v2); //-----消费适配器------ let v1 = vec![1, 2, 3]; let v1_iter = v1.iter(); let total: i32 = v1_iter.sum();//调用消费适配器sum来求和 println!("total = {}", total); //-----迭代适配器------ println!("++++++++++++"); let v1 = vec![1, 2, 3]; println!("v1 = {:?}", v1); let v2: Vec<_> = v1.iter().map(|x| x+1).collect(); println!("v2 = {:?}", v2); //------------------------ println!("++++++++++++"); let v1 = vec![1, 12, 3, 45]; println!("v1 = {:?}", v1); let v2: Vec<_> = v1.into_iter().filter(|x| *x > 5).collect(); println!("v2 = {:?}", v2); println!("Hello, world!"); }struct Counter { count: u32, } impl Counter { fn new() -> Counter { Counter {count: 0} } } impl Iterator for Counter { type Item = u32; fn next(&mut self) -> Option<Self::Item> { self.count += 1; if self.count < 6 { Some(self.count) } else { None } } } fn main() { let mut counter = Counter::new(); for i in (0..6) { if let Some(v) = counter.next() { println!("i = {}, v = {}", i, v); } else { println!("i = {}, at end", i); break; } } println!("Hello, world!"); } -
cargo
cargo build 编译 生成debug版本
如果想要生成release版本,需要cargo build --release
cargo run --release直接编译运行release版本
编译优化:在cargo.toml
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
默认dev(debug)版本优化级别为0,release版本优化级别为3
优化级别越高,编译时间越长(编译时间较短时候误差较大)
-
将包上传到crate.io
///三斜杠的注释 文档注释 发布包对函数和结构体
//!的注释 对整个模块的简要概述
cargo doc 生成doc
cargo doc --open
md格式的注释
crate的发布与撤回(此部分没有实际操作过,只讲步骤)
(1)创建Crates.io账号:通过Github账户注册,并通过cargo login ****** 来登陆
(2)发布前需要在Cargo.toml中增加描述:
[package]
name = "package_name"
version = "0.1.0"
license = "MIT" #Linux 基金会 的 Software Package Data Exchange (SPDX) 列出了可以使用的标识符
authors = ["linghuyichong"]
description = "some thing descript the package"
运行cargo publish来发布。
(3)撤回指定版本
cargo yank --vers 0.1.0 -
cargo工作空间
cargo run -p adder指定运行
具体代码见addr
-
智能指针
-
指针是一个包含内存地址的变量,这个地址指向一些其它的数据
智能指针是一类数据结构,它们表现类似于指针,但是也拥有额外的元数据,最明显的,它们拥有一个引用计数,引用计数记录智能指针总共有多少个所有者,并且当没有任何所有者时清除数据
普通引用和智能指针的一个额外区别是:引用知识只借用数据的指针,而智能指针则使用了他们指向的数据
-
智能指针通常使用结构体实现,智能指针区别于常规结构体的显著特征在于其实现了Deref和Drop trait
- Deref trait 允许智能指针结构体实例表现得像引用一个,这样就可以编写即用于引用,有用于智能指针的代码
- Drop trait允许我们自定义当智能指针离开作用域时执行的代码(简单理解就是析构)
-
几个标准库中的智能指针
Box
用于在堆上的分配 Rc
一个引用计数类型,其数据可以有多个拥有者 Ref
和RefMut 通过RefCell 访问,一个在运行时而不是在编译时执行借用规则的类型
-
-
Box智能指针
//1、最简单最直接的智能指针是box,其类型为Box<T>。box允许将值放在堆上而不是栈上,留着栈上的则是指向堆数据的指针。除了数据被存储在堆上外,box没有任何性能损失。 // //2、box适合用于如下场景: //(1)当有一个在编译时未知大小的类型,而又需要再确切大小的上下文中使用这个类型值的时候;(举例子:在一个list环境下,存放数据,但是每个元素的大小在编译时又不确定) //(2)当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候; //(3)当希望拥有一个值并只关心它的类型是否实现了特定trait而不是其具体类型时。 fn main() { let b = Box::new(5); //b存储于栈上,5存储在堆上,b指向5所在的内存 println!("b = {}", b); println!("Hello, world!"); }//box适合用于如下场景: //(1)当有一个在编译时未知大小的类型,而又需要再确切大小的上下文中使用这个类型值的时候;(举例子:在一个list环境下,存放数据,但是每个元素的大小在编译时又不确定) //(2)当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候; //(3)当希望拥有一个值并只关心它的类型是否实现了特定trait而不是其具体类型时。 //enum List { // Cons(i32, List), // Nil, //} enum List { Cons(i32, Box<List>), Nil, } //struct List { // int value; // struct List *next; // //struct List l; //}; // fn main() { use List::Cons; use List::Nil; //let list = Cons(1, Cons(2, Cons(3, Nil))); let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))); println!("Hello, world!"); } -
解引用
////实现Deref trait允许我们重载解引用运算符。 //let a: A = A::new();//前提:A类型必须实现Deref trait //let b = &a; //let c = *b;//解引用 fn main() { let x = 5; let y = &x; assert_eq!(5, x); assert_eq!(5, *y); //解引用 let z = Box::new(x); assert_eq!(5, *z); println!("Hello, world!"); }use std::ops::Deref; struct MyBox<T>(T); impl<T> MyBox<T> { fn new(x: T) -> MyBox<T> { MyBox(x) } } impl<T> Deref for MyBox<T> { type Target = T; fn deref(&self) -> &T { &self.0 } } fn main() { let x = 5; let y = MyBox::new(x); assert_eq!(5, x); assert_eq!(5, *y); let m = MyBox::new(String::from("Rust")); hello(&m); //将MyBox变为&String,再将String的解引用,变为字符串slice。 &str println!("Hello, world!"); } fn hello(name: &str) { println!("Hello, {}", name); } //解引用多态与可变性交互: //(1)当T:Deref<Target=U>时,从&T到&U //(2)当T:DerefMut<Target=U>时,从&mut T 到&mut U //(3)当T:Deref<Target=U>时,从&mut T到&U -
Drop trait
//1、Drop trait类似于其它语言中的析构函数,当值离开作用域的时候执行此函数的代码。 // struct Dog { name: String, //count: i32, } impl Drop for Dog{ fn drop(&mut self) { println!("Dog {} leave", self.name); //self.count -= 1; } } fn main() { let a = Dog{name: String::from("wangcai")}; { let b = Dog{name: String::from("dahuang")}; println!("0 +++++++++++++++++++"); } println!("1 +++++++++++++++++++"); println!("Hello, world!"); }struct Dog { name: String, } impl Drop for Dog { fn drop(&mut self) { println!("{} leave", self.name); } } //rust提供了std::mem::drop() fn main() { let a = Dog{name: String::from("wangcai")}; let b = Dog{name: String::from("dahuang")}; //b.drop(); drop(b); drop(a); println!("0 ++++++++++++++++++++++"); println!("Hello, world!"); } -
Rc智能指针
//enum List { // Cons(i32, Box<List>), // Nil, //} // //use crate::List::{Cons, Nil}; enum List { Cons(i32, Rc<List>), Nil, } use crate::List::{Cons, Nil}; use std::rc::Rc; fn main() { //let a = Cons(5, Box::new(Cons(10, Box::new(Nil)))); let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); //let b = Cons(3, Box::new(a)); //let b = Cons(3, Rc::clone(&a)); let b = Cons(3, a.clone()); //let c = Cons(4, Box::new(a)); let c = Cons(4, Rc::clone(&a)); println!("Hello, world!"); }//通过Rc<T>允许程序的多个部分之间只读的共享数据,因为相同位置的多个可变引用可能会造成数据竞争和不一致。 enum List { Cons(i32, Rc<List>), Nil, } use crate::List::{Cons, Nil}; use std::rc::Rc; fn main() { let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); println!("count after creating a = {}", Rc::strong_count(&a)); let b = Cons(3, Rc::clone(&a)); println!("count after bind to b, a count = {}", Rc::strong_count(&a)); { let c = Cons(4, Rc::clone(&a)); println!("count after bind to c, a count = {}", Rc::strong_count(&a)); } println!("count at end, a = {}", Rc::strong_count(&a)); println!("Hello, world!"); } -
RefCell
//1、内部可变性:允许在使用不可变引用时改变数据。 // //2、通过RefCell<T>在运行时检查借用规则(通常情况下,是在编译时检查借用规则),RefCell<T>代表其数据的唯一所有权。 //类似于Rc<T>,RefCell<T>只能用于单线程场景。 // //3、选择Box<T>、Rc<T>或RefCell<T>的理由: //Rc<T> 允许相同数据有多个所有者;Box<T> 和 RefCell<T> 有单一所有者。 //Box<T> 允许在编译时执行不可变或可变借用检查;Rc<T>仅允许在编译时执行不可变借用检查;RefCell<T> 允许在运行时执行不可变或可变借用检查。 //因为 RefCell<T> 允许在运行时执行可变借用检查,所以我们可以在即便 RefCell<T> 自身是不可变的情况下修改其内部的值。 #[derive(Debug)] enum List { Cons(Rc<RefCell<i32>>, Rc<List>), Nil, } use crate::List::{Cons, Nil}; use std::rc::Rc; use std::cell::RefCell; fn main() { let value = Rc::new(RefCell::new(5)); let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil))); let b = Cons(Rc::new(RefCell::new(6)), Rc::clone(&a)); let c = Cons(Rc::new(RefCell::new(7)), Rc::clone(&a)); println!("a before: {:?}", a); println!("b before: {:?}", b); println!("c before: {:?}", c); println!("+++++++++++++++++++"); *value.borrow_mut() += 10; println!("a after: {:?}", a); println!("b after: {:?}", b); println!("c after: {:?}", c); println!("Hello, world!"); } -
引用循环
#[derive(Debug)] enum List { Cons(i32, RefCell<Rc<List>>), Nil, } impl List{ fn tail(&self) -> Option<&RefCell<Rc<List>>> { match self { Cons(_, item) => Some(item), Nil => None, } } } use std::rc::Rc; use std::cell::RefCell; use crate::List::{Cons, Nil}; fn main() { let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil)))); println!("1, a rc count = {}", Rc::strong_count(&a)); println!("1, a tail = {:?}", a.tail()); { let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a)))); println!("2, a rc count = {}", Rc::strong_count(&a)); println!("2, b rc count = {}", Rc::strong_count(&b)); println!("2, b tail = {:?}", b.tail()); if let Some(link) = a.tail() { *link.borrow_mut() = Rc::clone(&b); } println!("3, a rc count = {}", Rc::strong_count(&a)); println!("3, b rc count = {}", Rc::strong_count(&b)); //println!("3, a tail = {:?}", a.tail()); //error } } -
弱引用
#[derive(Debug)] enum List { //Cons(i32, RefCell<Rc<List>>), Cons(i32, RefCell<Weak<List>>), Nil, } impl List { fn tail(&self) -> Option<&RefCell<Weak<List>>> { match self { Cons(_, item) => Some(item), Nil => None, } } } use std::rc::Rc; use std::cell::RefCell; use crate::List::{Cons, Nil}; use std::rc::Weak; fn main() { let a = Rc::new(Cons(5, RefCell::new(Weak::new()))); println!("1, a strong count = {}, weak count = {}", Rc::strong_count(&a), Rc::weak_count(&a)); println!("1, a tail = {:?}", a.tail()); let b = Rc::new(Cons(10, RefCell::new(Weak::new()))); if let Some(link) = b.tail() { *link.borrow_mut() = Rc::downgrade(&a); } println!("2, a strong count = {}, weak count = {}", Rc::strong_count(&a), Rc::weak_count(&a)); println!("2, b strong count = {}, weak count = {}", Rc::strong_count(&b), Rc::weak_count(&b)); println!("2, b tail = {:?}", b.tail()); if let Some(link) = a.tail() { *link.borrow_mut() = Rc::downgrade(&b); } println!("3, a strong count = {}, weak count = {}", Rc::strong_count(&a), Rc::weak_count(&a)); println!("3, b strong count = {}, weak count = {}", Rc::strong_count(&b), Rc::weak_count(&b)); println!("3, a tail = {:?}", a.tail()); println!("Hello, world!"); } //弱引用Weak<T> //特点: //(1)弱引用通过Rc::downgrade传递Rc实例的引用,调用Rc::downgrade会得到Weak<T>类型的智能指针,同时将weak_count加1(不是将strong_count加1)。 //(2)区别在于 weak_count 无需计数为 0 就能使 Rc 实例被清理。只要strong_count为0就可以了。 //(3)可以通过Rc::upgrade方法返回Option<Rc<T>>对象。 -
树形结构

浙公网安备 33010602011771号