rust

Rust

ownership

  • Each value in Rust has an owner.

  • There can only be one owner at a time.

  • When the owner goes out of scope, the value will be dropped.

1
2
let s1 = String::from("hello");
let s2 = s1;

在将 s1 赋值给 s2 时,s1 被移动到 s2 中,s1 不再有效。

如果需要 s1 仍然有效,可以使用 clone 方法:

1
2
let s1 = String::from("hello");
let s2 = s1.clone();

references and borrowing

1
2
let s1 = String::from("hello");
let s2 = &s1;

s2 是 s1 的引用,s2 指向 s1 的内存地址。如果 s1 不再有效,s2 也不再有效。

一个 mut 变量最多只能有一个可变引用,不可以有其它引用。

1
2
3
let mut s1 = String::from("abc");
let s2 = &mut s1;
let s3 = &mut s1; // error!!!

一个 mut 变量如果有一个不可变引用,那么 mut 变量不能被修改。

1
2
3
let mut s1 = String::from("abc");
let s2 = &s1;
s1.push_str("def"); // error!!!

slice

String 类型的 slice 是 &str 类型。

数组的 slice 是 &[T] 类型。

Traits

Traits 是 Rust 中一种抽象的概念,可以用来定义一组方法。

定义一个 Trait:

1
2
3
pub trait Summary {
fn summarize(&self) -> String;
}

实现一个 Trait:

1
2
3
4
5
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}

Trait 也可以有默认实现

可以在函数的参数中使用 Trait,确保参数实现了 Trait 的方法。

1
2
3
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}

在泛型中使用 Trait,确保 T 实现了 Trait 的方法。

1
2
3
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}

如果需要满足多个 Trait

1
2
3
4
5
6
pub fn notify(item: &(impl Summary + Display))
{
}
pub fn notify<T: Summary + Display>(item: &T)
{
}

也可以使用 where 关键字

1
2
3
4
5
6
7
8
9
fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32
{
}
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
}

利用 Traits 可以为泛型的特定类型定义特定方法

只有满足实现 Display 和 PartialOrd Trait 的 Pair 类型才能调用 cmp_display 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::fmt::Display;

struct Pair<T> {
x: T,
y: T,
}

impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self { x, y }
}
}

impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}

lifetime

返回值的生命周期不能超过任何一个参数的生命周期

1
2
3
4
5
6
7
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}

结构体对象不能超过它的成员的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct ImportantExcerpt<'a> {
part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
}

fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().unwrap();
let i = ImportantExcerpt {
part: first_sentence,
};
}

Lifetime Elision

rust 中某些情况可以省略生命周期参数,需要满足下面三条规则

  1. 编译器为所有引用参数分配一个生命周期参数

一个参数的函数获得一个生命周期参数:fn foo<’a>(x:&’a i32);具有两个参数的函数获得两个单独的生命周期参数:fn foo<’a, ‘b>(x:&’a i32, y:&’b i32);依此类推。

  1. 如果只有一个输入生命周期参数,它被被赋予所有输出生命周期参数:fn foo<’a>(x:&’a i32)-> &’a i32;

  2. 如果方法有多个输入生命周期参数,但其中一个是 &self 或 &mut self,那么 self 的生命周期被赋予给所有输出生命周期参数:fn foo<’a>(&self:&’a i32, y: &’b i32)-> &’a i32;

‘static 生命周期是一个特殊的生命周期,代表整个程序的生命周期。

Smart Pointers

Box

for allocating values on the heap

分配在堆上的值,适用于以下情况:

  1. 数据大小未知

  2. 大量数据需要转移,同时不想复制

  3. 不关心数据的具体类型,只需要实现特定 trait

Rust 在三种情况下找到类型和 trait 实现时会进行 deref 强制转换:

  • 当 T 时从 &T 到 &U:Deref<Target=U>

  • 当 T 时从 &mut T 到 &mut U:DerefMut<Target=U>

  • 当 T 时从 &mut T 到 &U:Deref<Target=U>

如果需要提前释放对象的内存,可以使用 drop 函数,drop(T)

Rc

a reference counting type that enables multiple ownership

使用 Rc::clone(&T) 方法增加引用计数,一般不使用 T.clone()。因为后者大多数情况下是深拷贝。

RefCell and RefCellMut(没看懂)

borrowing rules 在运行时检查,而不是编译时检查。

RefCell 也是 unique 的。

Rc 和 RefCell 都只在单线程中使用。

Concurrency

rust 使用 thread::spawn 创建线程

如果要在子线程中使用父线程的变量,需要在闭包前使用 move 关键字

通过 channel 通信

通过 Arc 包装 Mutex 实现多线程共享数据

Advanced Features

unsafe

1
2
3
unsafe {

}
  1. 解引用原始指针
1
2
*const
*mut
  1. 调用不安全函数或方法

不安全函数前有 unsafe 关键字

  1. 访问或修改可变静态变量

  2. 实现不安全 trait

  3. 访问 union 字段

高级 trait

  1. 在 trait 中定义指定占位符类型

  2. 默认泛型类型参数和运算符重载

  3. 完全限定语法与消歧义

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
trait Pilot {
fn fly(&self);
}

trait Wizard {
fn fly(&self);
}

struct Human;

impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.");
}
}

impl Wizard for Human {
fn fly(&self) {
println!("Up!");
}
}

impl Human {
fn fly(&self) {
println!("*waving arms furiously*");
}
}

fn main() {
let person = Human;
Pilot::fly(&person);
Wizard::fly(&person);
person.fly();
}

参考文档


rust
https://hanzhang-xyz.github.io/2024/10/21/rust/
Author
Han Zhang
Posted on
October 21, 2024
Licensed under