环境安装

运行 一个 init的文件

1
2
rustup toolchain install  stable-x86_64-pc-windows-gnu
rustup default stable-x86_64-pc-windows-gnu

rust语法

安装rust遇到的问题

1
2
rustup toolchain install stable-x86_64-pc-windows-gnu
rustup default stable-x86_64-pc-windows-gnu

shadowing特性

声明相同名字的变量,前面的变量会被隐藏

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13


fn main() {
  let x = "  ";
  println!("hello world");
  
  let x = 666;

  println!("the value is {} ",x);



}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

fn call_func(x:i32) {
  println!("integer value is {}",x);
}
fn main() {
   let a = [1,2,3];
   call_func(a[0]);



}

数据类型

rust语言是静态语言,编译时候需要知道所有变量

  • rust 有两种基础的浮点类型,也就是含有小数部分的类型
    • -f32,32位,单精度
    • -f64,64位,双精度
  • Rust默认是f64,因为现在的cpu f64和 f32速度差不多,精度更高

字符类型

  • Rust语言中 char类型被用来描述语言中最基础的单个字符
  • 字符类型的字面值使用单引号
  • 占用4个字节大小
  • 是unicode 表两只,可以表示比 ascii多的多的字符内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn main() {
    let s = String::from("hello world");
    println!("hello world {}",first_word(&s));
}

fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();
    for (i,&item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }
    s.len()
}

rust语法结构

1
2
3
4
5
6
7
8
fn main() {


    let s = String::from("hello world");
    let s2 = s;
    //会报错,因为  值的所有权被转移了
    println!(" hello {}",s)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
fn main() {


    let s = String::from("hello world");
    {
        let s2 = s;
        //s 的内存将会被这个代码块回收
    }
    //会报错,因为  值的所有权被转移了
    println!(" hello {}",s)
}

智能指针

智能指针课程参考

中序遍历示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Definition for a binary tree node.
// #[derive(Debug, PartialEq, Eq)]
// pub struct TreeNode {
//   pub val: i32,
//   pub left: Option<Rc<RefCell<TreeNode>>>,
//   pub right: Option<Rc<RefCell<TreeNode>>>,
// }
//
// impl TreeNode {
//   #[inline]
//   pub fn new(val: i32) -> Self {
//     TreeNode {
//       val,
//       left: None,
//       right: None
//     }
//   }
// }
use std::rc::Rc;
use std::cell::RefCell;
impl Solution {
    pub fn inorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
        let mut mu = vec![];
        Solution::dfs(root.clone(),& mut mu);
        mu 
    }
    pub fn dfs(root :Option<Rc<RefCell<TreeNode>>> ,res:&mut Vec<i32>) {
        if let Some(node) = root {
            let x = node.borrow();
            Solution::dfs(x.left.clone(),res);
            res.push(x.val);
            Solution::dfs(x.right.clone(),res);
        }
    }
}

rc学习视频

https://pic1.zhimg.com/80/v2-03aa976f85a5e6400f64fb2f3677c6b8_720w.jpg

reference counting

Rc<T>支持多重所有权,它名称中的Rc是Referencecounting(引用计数)的缩写。对于了解垃圾回收概念的同学理解起来会更顺畅一些,Rc<T>类型会在内部维护一个引用次数计数器,用于确认这个值是否仍在使用。如果对一个值的引用次数为零,那么就意味着这个值可以被安全地清理掉,而不会触发引用失效的问题:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::rc::Rc; // 引入Rc
#[derive(Debug)]
enum List {
  Cons(i32, Rc<List>), // 替换Box为Rc
  Nil
}

// 创建Rc实例
let a = Rc::new(List::Cons(5,
  Rc::new(List::Cons(10,
    Rc::new(List::Nil)
  ))
));

// 这里的Rc::clone只是增加的引用计数,虽然使用a.clone也可以实现,但是数据会被深拷贝
let b = List::Cons(3, Rc::clone(&a));

// 再次增加引用次数
let c = List::Cons(4, Rc::clone(&a));

println!("{:?}", b); // Cons(3, Cons(5, Cons(10, Nil)))
println!("{:?}", c); // Cons(4, Cons(5, Cons(10, Nil)))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
let a = Rc::new(List::Cons(5,
  Rc::new(List::Cons(10,
    Rc::new(List::Nil)
  ))
));

println!("创建a之后的引用计数:{}", Rc::strong_count(&a));
// 创建a之后的引用计数:1

let b = List::Cons(3, Rc::clone(&a));
println!("创建b之后的引用计数:{}", Rc::strong_count(&a));
// 创建b之后的引用计数:2

// 进入新的作用域
{
 let c = List::Cons(2, Rc::clone(&a));
 println!("创建c之后的引用计数:{}", Rc::strong_count(&a));
  // 创建c之后的引用计数:3
} // c离开作用域时自动将引用计数减1。

println!("销毁c之后的引用计数:{}", Rc::strong_count(&a));
// 销毁c之后的引用计数:2

理解 Box、Rc、RefCell

image-20220329005622017

参考视频第11分钟

box类型使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use std::borrow::{Borrow, BorrowMut};
use std::rc::Rc;
use crate::Node::{Cons, Nil};

// struct Node<T> {
//     value: T,
//     left: Option<Rc<Node<T>>>,
//     right: Option<Rc<Node<T>>>,
// }
#[derive(Debug)]
enum Node {
    Cons(i32, Box<Node>),
    Nil,
}

fn main() {
    //box 是一种智能指针,Safe rust中 没有显式的堆内存分配函数, 用 Box是唯一一种方式
    let x: Box<i32> = Box::new(42);
    let y = *x;// x也叫装箱类型
    println!("{:?}", y);
    //通过 *操作符 用来解引用
    let list = Cons(1,Box::new(Nil));

    println!("{:?}",list.borrow() );

}

enum 数据结构

看代码,rust 不像java,数据可以直接附加到枚举的变体中,而不是那种单例类。

参考学习视频

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
enum Book{
    Yuwen(String), //语文
    Shuxue(String),//数学
    
}

fn main(){
    println!("Rust Programming");
    //rust 的 enum是可以 用户自己设置值的,不像java 那种单例类
    //数据可以直接附加到枚举的变体中
    let b1=Book::Yuwen(String::from("床前明月光"));
    println!("{}",work(b1));
    let b2=Book::Shuxue(String::from("x+y=0"));
    println!("{}",work(b2));
}
fn work(book:Book)->String{
    match book{
        Book::Yuwen(s1)=>s1,
        Book::Shuxue(s2)=>s2,
    }
}

Option 数据结构

Option是rust非常好用的数据结构,用来解决 Null 空指针问题,是rust安全基石重要一环。其本质是一个 Enum 结构。本文对option进行模式匹配用于获取 option 包装的值的简单用法。

1
2
3
4
pub enum Option<T> {
    None,
    Some(T),
}

模式匹配

Option 是一个Enum,通过模式匹配获取其变体

Some(T) 变体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let opt = Some("hello".to_string());
match opt {
    Some(x) => println!("Some: x={}", x), // Some: x=hello
    None => println!("None")
}
// 判断 Some 还是 None
let opt:Option<String> = None;
match opt {
    Some(x) => println!("Some: x={}", x), 
    None => println!("None") // None
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
enum Coin {
    Penny,
    Dime,
    Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
    match {
        Coin::Penny => 1,
        Coin::Dime => 5,
        Coin::Quarter => 25,
    }
    //依次按照分支进行匹配
}
fn main() {
    
}

绑定值写法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
fn plus_one(x: Option<i32>) -> Option<i32> { 
    match x {
        None => None,          
        Some(i) => Some(i + 1), 
        //上面相当于 将Option 里面存的东西赋值给 i ,就可以使用 i这个变量了
    }
}

let five = Some(5);
let six = plus_one(five); 
let none = plus_one(None);

if let 写法

只关心一种匹配的时候使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/*
let v = Some(0u8);
match v {
 	Some(3) => println!("hello"),
 	_ => (),
}
*/
if let Some(3) = v {
    println!("three");
}

unwarp方法

Option 有很多有用的方法。unwarp 方法用于获取 Some(x) 中 的 x 值。如果 Option是 None 变体,则该方法会 pannic。

1
2
3
let opt = Some("hello".to_string());
let s = opt.unwrap();
println!("{}", s); // s

opt 通过 unwarp 方法获取变体 Some(x) 中的 x。若 opt 是 None 变体,unwarp 方法会pannic

uwranp的源码:

从 unwarp的源码可以看出,它本质也是模式匹配的一种简写。

1
2
3
4
5
6
pub const fn unwrap(self) -> T {
    match self {
        Some(val) => val,
        None => panic!("called `Option::unwrap()` on a `None` value"),
    }
}

所有权

Option的模式匹配和 unwarp 方法涉及所有权move语义。(x指没有实现 Copy trait的类型)

就像赋值,参数传递一样。直接模式匹配会涉及所有权move

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let opt = Some("hello".to_string());
let s = opt.unwrap();

println!("{:?}", opt);
// ---下面是报错信息
48  |     let opt = Some("hello".to_string());
    |         --- move occurs because `opt` has type `Option<String>`, which does not implement the `Copy` trait
49  |     let s = opt.unwrap();
    |                 -------- `opt` moved due to this method call
50  | 
51  |     println!("{:?}", opt);
    |                      ^^^ value borrowed here after move
    |

Option 是 rust 类型安全重要思想的体现之一。它本质是一个 Enum 类型,有两个变体,Some(x) 和 None。当表示没有值的时候,可以使用 None。其语义类似其他语言如 Python的None,Golang 的 nil, java 的null。但是又跟其他语言有本质的不同。rust 的 None 是 Option 类型。而不是 其他任何类型。而其他语言的 None nil 可以是任何其他类型或引用类型。Null 可以是 字串,也可以是 指针。这就埋下了很多安全隐患。

Rust 的中表示可有可无的时候使用 Option。有值的时候需要使用 Some 变体。解出 Some(x) 中的 x 值方法是模式匹配。同时标注库也提供了便捷方法如 unwrap。

1
2
3
4
fn main() {
    let y: Option<i8> = Some(5);
    let a: Option<i8> = None;
}