Skip to main content

Rust Book Datastructure - Arc

Rust
KIGA
Author
KIGA
This is a personal blog, intended for sharing.
Table of Contents

Rc 和 Arc 源码对比
#

// Rc源码片段
impl<T: ?Sized> !marker::Send for Rc<T> {}
impl<T: ?Sized> !marker::Sync for Rc<T> {}
// Arc源码片段
unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}

! 代表移除特征的相应实现,上面代码中 Rc<T> 的 Send 和 Sync 特征被特地移除了实现 Arc<T> 则相反,实现了 Sync + Send

为裸指针实现Send
#

unsafe 代码块包裹,实现Send 和Sync 是 unsafe 特征

use std::thread;
#[derive(Debug)]
struct MyBox(*mut u8);
unsafe impl Send for MyBox {}
fn main() {
   let p = MyBox(5 as *mut u8);
   let t = thread::spawn(move || {
       println!("{:?}", p);
   });
   t.join().unwrap();
}

为裸指针实现Sync
#

use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
#[derive(Debug)]
struct MyBox(*const u8);
// 访问的引用实际上还是对主线程中的数据的借用,转移进来的仅仅是外层的智能指针引用
// 为 MyBox 实现 Sync
unsafe impl Sync for MyBox {}
fn main() {
    let b = &MyBox(5 as *const u8);
    let v = Arc::new(Mutex::new(b));
    let t = thread::spawn(move || {
        let _v1 = v.lock().unwrap();
    });
    t.join().unwrap();
}
  • 实现 Send 的类型可以在线程间安全的传递其所有权, 实现 Sync 的类型可以在线程间安全的共享(通过引用)
  • 绝大部分类型都实现了 Send 和 Sync ,常见的未实现的有:裸指针、 Cell 、 RefCell 、 Rc
  • 可以为自定义类型实现 Send 和 Sync ,但是需要 unsafe 代码块
  • 可以为部分 Rust 中的类型实现 Send 、 Sync ,但是需要使用 newtype

全局变量
#

const MAX_ID: usize = usize::MAX / 2;
// 静态变量不会被内联,在整个程序中,静态变量只有一个实例,所有的引用都会指向同一个地址
// 存储在静态变量中的值必须要实现 Sync trait
static mut REQUEST_RECV: usize = 0;
fn main() {
    println!("用户ID允许的最大值是{}", MAX_ID);
    unsafe {
        REQUEST_RECV += 1;
        assert_eq!(REQUEST_RECV, 1);
    }
}

想要全局计数器、状态控制等功能,又想要线程安全的实现,原子类型是非常好的办法。

use std::sync::atomic::{AtomicUsize, Ordering};
static REQUEST_RECV: AtomicUsize = AtomicUsize::new(0);
fn main() {
    for _ in 0..100 {
        REQUEST_RECV.fetch_add(1, Ordering::Relaxed);
    }
    println!("当前用户请求数{:?}", REQUEST_RECV);
}
use std::sync::atomic::{AtomicUsize, Ordering};
struct Factory {
    factory_id: usize,
}
static GLOBAL_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
const MAX_ID: usize = usize::MAX / 2;
fn generate_id() -> usize {
    // 检查两次溢出,否则直接加一可能导致溢出
    let current_val = GLOBAL_ID_COUNTER.load(Ordering::Relaxed);
    if current_val > MAX_ID {
        panic!("Factory ids overflowed");
    }
    let next_id = GLOBAL_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
    if next_id > MAX_ID {
        panic!("Factory ids overflowed");
    }
    next_id
}
impl Factory {
    fn new() -> Self {
        Self {
            factory_id: generate_id(),
        }
    }
}

fn main() {
    let factory = Factory::new();
    println!("factory id: {}", factory.factory_id);
    println!("factory id: {}", factory.factory_id);
}

lazy_static
#

use lazy_static::lazy_static;
use std::collections::HashMap;
lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
}
pub fn lazy_test() {
    // 首次访问`HASHMAP`的同时对其进行初始化
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    // 后续的访问仅仅获取值,再不会进行任何初始化操作
    println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap());
}
// The entry for `0` is "foo".
// The entry for `1` is "bar".

函数中返回全局变量
#

#[derive(Debug)]
struct Config {
    a: String,
    b: String,
}
static mut CONFIG: Option<&mut Config> = None;
fn init() -> Option<&'static mut Config> {
    let c = Box::new(Config {
        a: "A".to_string(),
        b: "B".to_string(),
    });
    Some(Box::leak(c))
}
fn main() {
    unsafe {
        CONFIG = init();
        println!("{:?}", CONFIG)
    }
}

错误处理
#

fn main() {
    {
        // and_then with Option
        let s1 = Some("some1");
        let s2 = Some("some2");
        let fn_some = |_| Some("some2"); // 类似于: let fn_some = |_| -> Option<&str> {Some("some2") };
        let n: Option<&str> = None;
        let fn_none = |_| None;
        assert_eq!(s1.and_then(fn_some), s2); // Some1 and_then Some2 = Some2
        assert_eq!(s1.and_then(fn_none), n); // Some and_then None = None
        assert_eq!(n.and_then(fn_some), n); // None and_then Some = None
        assert_eq!(n.and_then(fn_none), n); // None1 and_then None2 = None1
                                            // and_then with Result
        let o1: Result<&str, &str> = Ok("ok1");
        let o2: Result<&str, &str> = Ok("ok2");
        let fn_ok = |_| Ok("ok2"); // 类似于: let fn_ok = |_| -> Result<&str, &str> {Ok("ok2") };
        let e1: Result<&str, &str> = Err("error1");
        let e2: Result<&str, &str> = Err("error2");
        let fn_err = |_| Err("error2");
        assert_eq!(o1.and_then(fn_ok), o2); // Ok1 and_then Ok2 = Ok2
        assert_eq!(o1.and_then(fn_err), e2); // Ok and_then Err = Err
        assert_eq!(e1.and_then(fn_ok), e1); // Err and_then Ok = Err
        assert_eq!(e1.and_then(fn_err), e1); // Err1 and_then Err2 = Err1
    }
    // filter 用于对 Option 进行过滤
    {
        let s1 = Some(3);
        let s2 = Some(6);
        let n = None;
        let fn_is_even = |x: &i8| x % 2 == 0;
        assert_eq!(s1.filter(fn_is_even), n); // Some(3) -> 3 is not even -> None
        assert_eq!(s2.filter(fn_is_even), s2); // Some(6) -> 6 is even -> Some(6)
        assert_eq!(n.filter(fn_is_even), n); // None -> no value -> None
    }
    // map 可以将 Some 或 Ok 中的值映射为另一个
    {
        let s1 = Some("abcde");
        let s2 = Some(5);
        let n1: Option<&str> = None;
        let n2: Option<usize> = None;
        let o1: Result<&str, &str> = Ok("abcde");
        let o2: Result<usize, &str> = Ok(5);
        let e1: Result<&str, &str> = Err("abcde");
        let e2: Result<usize, &str> = Err("abcde");
        let fn_character_count = |s: &str| s.chars().count();
        assert_eq!(s1.map(fn_character_count), s2); // Some1 map = Some2
        assert_eq!(n1.map(fn_character_count), n2); // None1 map = None2
        assert_eq!(o1.map(fn_character_count), o2); // Ok1 map = Ok2
        assert_eq!(e1.map(fn_character_count), e2); // Err1 map = Err2
    }
    // map 可以将 Some 或 Ok 中的值映射为另一个
    {
        let s1 = Some("abcde");
        let s2 = Some(5);
        let n1: Option<&str> = None;
        let n2: Option<usize> = None;
        let o1: Result<&str, &str> = Ok("abcde");
        let o2: Result<usize, &str> = Ok(5);
        let e1: Result<&str, &str> = Err("abcde");
        let e2: Result<usize, &str> = Err("abcde");
        let fn_character_count = |s: &str| s.chars().count();
        assert_eq!(s1.map(fn_character_count), s2); // Some1 map = Some2
        assert_eq!(n1.map(fn_character_count), n2); // None1 map = None2
        assert_eq!(o1.map(fn_character_count), o2); // Ok1 map = Ok2
        assert_eq!(e1.map(fn_character_count), e2); // Err1 map = Err2
    }
    {
        const V_DEFAULT: u32 = 1;
        let s: Result<u32, ()> = Ok(10);
        let n: Option<u32> = None;
        let fn_closure = |v: u32| v + 2;
        assert_eq!(s.map_or(V_DEFAULT, fn_closure), 12);
        assert_eq!(n.map_or(V_DEFAULT, fn_closure), V_DEFAULT);
    }
    {
        let s = Some(10);
        let n: Option<i8> = None;
        let fn_closure = |v: i8| v + 2;
        let fn_default = || 1;
        assert_eq!(s.map_or_else(fn_default, fn_closure), 12);
        assert_eq!(n.map_or_else(fn_default, fn_closure), 1);
        let o = Ok(10);
        let e = Err(5);
        let fn_default_for_result = |v: i8| v + 1; // 闭包可以对 Err 中的值进行处理,并返回一个新值
        assert_eq!(o.map_or_else(fn_default_for_result, fn_closure), 12);
        assert_eq!(e.map_or_else(fn_default_for_result, fn_closure), 6);
    }

    {
        let s = Some("abcde");
        let n: Option<&str> = None;
        let fn_err_message = || "error message";
        let o: Result<&str, &str> = Ok("abcde");
        let e: Result<&str, &str> = Err("error message");
        assert_eq!(s.ok_or_else(fn_err_message), o); // Some(T) -> Ok(T)
        assert_eq!(n.ok_or_else(fn_err_message), e); // None -> Err(default)
    }
}
use std::fs::File;
use std::io;
#[derive(Debug)]
struct AppError {
    kind: String,    // 错误类型
    message: String, // 错误信息
}
// 为 AppError 实现 std::convert::From 特征,由于 From 包含在 std::prelude 中,因此可以直接简化引入。
// 实现 From<io::Error> 意味着我们可以将 io::Error 错误转换成自定义的 AppError 错误
impl From<io::Error> for AppError {
    fn from(error: io::Error) -> Self {
        AppError {
            kind: String::from("io"),
            message: error.to_string(),
        }
    }
}
fn main() -> Result<(), AppError> {
    // ? 可以将错误进行隐式的强制转换
    // File::open 返回的是 std::io::Error , 我们并没有进行任何显式的转换,它就能自动变成AppError ,这就是 ? 的强大之处
    let _file = File::open("nonexistent_file.txt")?;
    Ok(())
}
use std::fs::File;
use std::io::{self, Read};
use std::num;
#[derive(Debug)]
struct AppError {
    kind: String,
    message: String,
}
impl From<io::Error> for AppError {
    fn from(error: io::Error) -> Self {
        AppError {
            kind: String::from("io"),
            message: error.to_string(),
        }
    }
}
impl From<num::ParseIntError> for AppError {
    fn from(error: num::ParseIntError) -> Self {
        AppError {
            kind: String::from("parse"),
            message: error.to_string(),
        }
    }
}
fn main() -> Result<(), AppError> {
    let mut file = File::open("hello_world.txt")?;
    let mut content = String::new();
    file.read_to_string(&mut content)?;
    let _number: usize;
    _number = content.parse()?;
    Ok(())
}

// 01. 若 hello_world.txt 文件不存在
Error: AppError { kind: "io", message: "No such file or directory (os error 2)" }
// 02. 若用户没有相关的权限访问 hello_world.txt
Error: AppError { kind: "io", message: "Permission denied (os error 13)" }
// 03. 若 hello_world.txt 包含有非数字的内容,例如 Hello, world!
Error: AppError { kind: "parse", message: "invalid digit found in string" }

指针
#

创建裸指针是安全的行为,而解引用裸指针才是不安全的行为 :

fn main() {
    let mut num = 5;
    let r1 = &num as *const i32;

    unsafe {
        println!("r1 is: {}", *r1);
    }

    let r2 = &mut num as *mut i32;
    unsafe {
        println!("r1 is: {}", *r1);
    }
}

基于智能指针创建裸指针
#

let a: Box<i32> = Box::new(10);
// 需要先解引用a
let b: *const i32 = &*a;
// 使用 into_raw 来创建
let c: *const i32 = Box::into_raw(a);