Rust学习

并发

Rust无畏并发:允许编写没有细微BUG的代码,并在不引入新BUG的情况下易于重构

多线程

实现多线程的方式:使用Os的Api创建线程, 1:1模型,2.语言自己实现的线程, M:N模型

Rust标准库仅提供1:1线程模型,通过Thread::spawn创建新线程,参数为闭包(新线程中运行的代码

fn main() {
    let a = || {
        loop {
            println!("我是子进程");
            // 暂停两秒
            thread::sleep(Duration::from_secs(2));
        }
    };
    let son_thread = thread::spawn(a);
    loop {
        println!("我是父进程");
        thread::sleep(Duration::from_secs(1));
    }
    // join干哈的我就不多说了
    son_thread.join();
}
我是父进程
我是子进程
我是父进程
我是父进程

必报的子线程可以贡献同一作用域下的其他线程参数,这是闭包的特性哦应该没有忘记把。但是在多线程中我们还需要Move来传递参数

fn main() {
    let data = String::from("我是主线程数据");
    // let a = move || {
    let a = || {
            println!("获取主线程的数据: {}", data);
    };
    let son_thread = thread::spawn(a);
    son_thread.join();
}
let a = || {
   |             ^^ may outlive borrowed value `data`
8  |             println!("获取主线程的数据: {}", data);
   |                                               ---- `data` is borrowed here

这里的报错的意思指:我们在子线程中调用的这个数据可能在子线程运行完毕之前就被del了,Rust编译器连这都想到了确实很细致。我们如果一定要获得参数的化使用Move 获取此参数的所有权即可

消息传递

消息传递是一种很流行的保证安全并发的线程通讯技术。线程彼此之间通过发送消息完成通讯。可以理解为Python中的携程

Rust 使用Channel(标准库提供)实现进程通讯。Channel包含发送端域接收单,调用发送端的方法就是发送数据,接收端会检查和接受收到的数据。如果发送,接受任意一端被丢弃,Channel就关闭了

使用mpsc::channel创建Channel (多个生产者,一个消费者), 返回一个元组,一个发送端,一个接收端。

fn main() {
    let (sender,receiver) = mpsc::channel();
    let a = move || {
        loop {
            //返回Result, 有问题就甩Err
            sender.send(String::from("Hello"));
            // 这里如果上面发送的是变量的化,那所有权已经在receiver手里了
            println!("获取主线程发送数据: Hello");
            thread::sleep(Duration::from_secs(1));
        }
    };
    let son_thread = thread::spawn(a);
    loop {
        // 阻塞当前线程知道Channel中有值送到, 发送端关闭则返回错误
        let data = receiver.recv().unwrap();
        println!("收到数据: {}",data);
    }
    son_thread.join();
}
收到数据: Hello
获取主线程发送数据: Hello
获取主线程发送数据: Hello
收到数据: Hello

对于发送者,我们可以使用克隆创建多个发送者,毕竟是多生产者单消费者

共享状态的并发

这一节讲的就是锁,利用Mutex 进行上锁,并使用ARC使其s拥有多重所有权.我的评价是不如通讯、不如携程。

ooj 面向对象

面向对象不是简单的有类有函数就OJBK了, 面向对象三大特性最少要保证吧:封装,继承,堕胎。关于Rust的面向对象特性其实是一个比较矛盾的存在。

  • 封装:调用对象外部的代码无法直接访问对象内部的实现细节,唯一与对象交互的方法就是公开的API. Rust中我们引用的时候不是只能引用被pub修饰的方法,或者说mod么,在这种情况下我们可以认为Rust是具有封装特性的
  • Rust中没有继承的概念。继承的目的主要是代码复用较少代码量, 但是Rust未见过啥结构体,枚举类型继承的情况。Rust本身虽然没有复用,但是我们可以使用trait定义加上泛形试下代码的共享 。同时我们可以覆盖已经实现的trait, 只能说实现了一定程度的继承。
  • 多态:Rust中使用泛形和trait约束限定多态。

trait对象其实更多像接口或抽象类定义,在我们上一张学了Box之后就可以采用Box进行泛化了。BOx进行泛化保证同一个Vec中可以存储不同类型, 这种派发与普通的trait泛形约束相比较属于动态派发,无法在编译时确定类型。对于这种trait,Rust限定了两条法则保证安全

  1. 方法的返回类型是Self
  2. 方法中不包含任何泛形类型参数
// 一个泛形的例子
use crate::type2::Name2;

trait whoami{
    fn print_my_type(&self);
}
struct  type1{
    Name1:String,
}

impl whoami for type1 {
    fn print_my_type(&self) {
        println!("I'm type1");
    }
}
enum type2{
    Name2(Vec<String>),
}

impl whoami for type2 {
    fn print_my_type(&self) {
        println!("I'm type 2")
    }
}

struct type_done_whoami_trait{
    // 完成了vec的都可以放到type_vec中
    type_vec:Vec<Box<dyn whoami>>,
}

impl type_done_whoami_trait{
    fn new() -> type_done_whoami_trait{
        let a = type1{ Name1: String::new()};
        let c = type1{ Name1: String::new()};
        let b = type2::Name2(vec![String::new()]);
        type_done_whoami_trait {
            type_vec: vec![Box::new(a),Box::new(b),Box::new(c)]
        }
    }
}

fn main() {
    let c = type_done_whoami_trait::new();
    for p in c.type_vec{
        // 这里直接 p.print_my_type()也是可以的
        (*p).print_my_type();
    }
}

经典面向对象的模式不适合Rust,使用需谨慎哦

你可能感兴趣的:(rust)