表达式

Rust是表达式语言,所有语句都是表达式,所有语句都有值。if和match也能产生值。

let status = 
    if cpu.temperature <= MAX_TEMP {
        HttpStatus::OK
    } else {
        HttpStatus::ServerError
    };

表达式块{...}的最后一行省略分号,则块的值为最后这表达式的值。块的最后一加上分号,则块的值为空()

#? 嵌套的内层fn不能访问外层fn的局部变量或参数。

a..b是前闭后开区间,a..=b是闭区间

for迭代集合,则循环变量是转移值。 for迭代集合的引用,则循环变量也是引用。 for迭代集合的mut引用,则循环变量也是mut引用。

函数返回类型-> !表示函数永远也不会返回。

turbofish:::<T>在Rust无法推断类型时提供帮助

return Vec::<i32>::with_capacity(100);

与C不一样:

  • 按位非!x,而不是~x
  • 位操作的优先级高于比较操作,x & BIT != 0表示(x & BIT) != 0

类型转换使用as关键字


错误处理

panic用于处理永远不该发生的错误

println!()打印错误时,格式描述符{}只显示简略的错误信息,{:?}会显示错误信息的std::fmt::Debug

Result<T,E>是一个枚举类型 result?:成功值T,否则让错误向外传播

let weather = get_weather(hometown)?;
// 等价于
let weather = match get_weather(hometown) {
    Ok(success_value) => success_value,
    Err(err) => return Err(err)
}

result.unwrap()result.expect(message):成功值T,否则panic


包和模块

包主要解决项目间代码共享的问题,模块主要解决项目内代码组织的问题。

可以一次导入多个模块:use std::collections::{HashMap, HashSet};

子模块可以访问其父模块中的私有特性项,但必须通过名字导入每一项。use super::*;只会导入那些被标记为pub的特性项。


结构体

通过impl定义方法

内部修改能力

需要在一个不可修改的值内部有一个小小的可修改数据 Cell<T>RefCell<T>


枚举与模式

像C的union,但类型安全 只能使用match模式访问枚举

最常用的两个泛型枚举:

enum Option<T> {
    None,
    Some(T)
}
 
enum Result<T, E> {
    Ok(T),
    Err(E)
}

闭包

fn(&City) -> bool    // fn类型(仅函数)
Fn(&City) -> bool    // Fn特型(包含函数和闭包) 

由于每个闭包都有自己的类型,使用闭包的代码通常需要泛型


并发

并行fork-join

join等待线程完成

panic不会自动传播到父线程,而是毒化父线程,在父线程中体现为Result(err)。

通道

通道是把值从一个线程发送到另一个线程的单向管道,是一个线程安全的队列。

// channel是无限大小队列,不阻塞生产者
use std::sync::mpsc::channel;
let (sender, receiver) = channel();
 
// sync_channel是有限大小队列,通道满时阻塞生产者
use std::sync::mpsc::sync_channel;
let (sender, receiver) = sync_channel(100);

mpsc指multi-producer, single-consumer(多生产者,单消费者)

Sender<T>实现了Clone特型。要获得一个有多个发送者的通道,只需创建一个常规通道,然后再克隆发送者,需要多少就克隆多少。可以把每个sender值转移到不同的线程。 Receiver<T>无法克隆,因此如果需要多个线程从同一个通道接收值,就需要使用Mutex

共享可变状态

互斥量、读写锁、条件变量、原子整数

数据争用(data race):多读与一写同一块内存 竞态条件(race condition):运行结果取决于线程的执行时机

条件变量

等待条件变量的标准写法:

while !guard.has_data() {
    guard = self.has_data_condvar.wait(guard).unwrap();
}

wait()方法释放了互斥量guard,然后在返回前又重新获取了它


特型和泛型

特型(trait)是Rust的接口。

特型对象是一个胖指针(指向值的指针,指向该值类型虚表的指针)。在C++中,虚拟表指针vptr被保存为结构体的一部分。而Rust使用胖指针,结构体除了自身字段外没有别的。这样,一个结构体能够实现很多特型而不必包含同样多的vptr。即使像i32这样没有足够空间容纳vptr的类型都可以实现特型。


参考

  • 《Programming Rust: Fast, Safe Systems Development》