rust Arc、Rc和Cell在web开发中使用到的场景

在web开发中常见的一场景:一个Person 实体有一个Vec

的属性,

#[derive(Clone, Debug)]
struct Person {
    addrs: Vec
} #[derive(Debug)] struct Address { //person_id:String, 根据用户ID获取到所有地址 name: String, }

我们一般会有一个业务,获取所有Vec返回给用户,每个Person对象可以获取根据person_id获取到所有address。下面代码是套用其它语言的经验写的代码:

struct Person {
    id: String,
    name: String,
    address: Option>,
}

#[derive(Clone)]
struct Address {
    id: String,
    user_id: String,
    name: String,
}

fn main() {
    let persons = get_person_all();
    let address = get_address_all();

    for mut p in persons {
        let mut addrs = vec![];//会一直复制address中的数据
        for addr in &address {
            if p.id.eq(&addr.user_id) {
                addrs.push((*addr).clone());//会一直复制address中的数据
            }
        }
        p.address = Some(addrs);
    }
}

fn get_person_all() -> Vec {
    vec![Person { id: "id".into(), address: None, name: "rust".into() }]
}

fn get_address_all() -> Vec
{ vec![Address { id: "id".into(), user_id: "userid".into(), name: "address".into() }] }

 上面会把Vec

中的数据复制后放入person对象中。这样当数据量大时,确实会造成大量的内在复制。

用ARC改进后的代码:

use std::sync::Arc;
use std::thread;
use std::time::Duration;

fn main() {
    {
        create_data();
    }
    thread::sleep(Duration::from_secs(5));
}


fn create_data() {
    let address = vec![Address { name: "rust".into() }, Address { name: "golang".into() }, Address { name: "java".into() }];
    let address = address.into_iter().map(|addr| Arc::new(addr)).collect::>(); ///在这里转化一下

    let mut persons = vec![];

    for i in 0..10 {

        let mut addrs = vec![];

        addrs.push(address[i % 3].clone());

        let p = Person { addrs };

        let clone_p=p.clone();

        persons.push(p);

        thread::spawn(move|| {
            thread::sleep(Duration::from_secs(2));
            println!("{:?}", clone_p)
        });
    }
}
#[derive(Clone, Debug)]
struct Person {
    addrs: Vec>//修改使用成ARC,因为会跨线程传递或clone所以用Arc
}

当时有想到使用RC或ARC,但觉得person中的属性addrs中的每个Address对象我有可能再更改,这样维护起来可能麻烦。后来在群里和大家讨论,又理了理,觉得Rc或Arc是可行的,就写了上面的demo验证了下。

而如果想修改addrs容器里的值,那么就配合cell或refcell和Mutex,看自己使用场景(深入浅出Rust这本书第15章节专门有介绍)。


#[derive(Clone, Debug)]
struct Person {
    addrs: Vec>>//这样就可以共享修改了
}

以上有问题,欢迎指正,这篇就是为了记录下使用rust中不套用其它语言经验,而需要用rust的方式来解决问题。

你可能感兴趣的:(rust思想)