Rust 程式設計,Option 學習

linghuyichong發表於2020-04-08

影片地址

頭條地址:https://www.ixigua.com/i676544267458235648...
B站地址:https://www.bilibili.com/video/av78062009?...
網易雲課堂地址:https://study.163.com/course/introduction....

github地址

github地址

介紹

Option型別代表了一個可選的值,每個Option要麼是一個Some中包含一個值,要麼是一個None。Option的定義如下:

pub enum Option<T> {
    None,
    Some(T),
}

用法

Option主要有以下一些用法:

  • 初始化值;

  • 作為在整個輸入範圍內沒有定義的函式的返回值;

  • 作為返回值,用None表示出現的簡單錯誤;

  • 作為結構體的可選欄位;

  • 作為結構體中可借出或者是可載入的欄位;

  • 作為函式的可選引數;

  • 代表空指標;

  • 用作複雜情況的返回值。

此處,我們舉例說明一下“作為結構體可借出或者是可載入的欄位”。

use std::thread;
use std::time::Duration;

struct Worker {
    thread: thread::JoinHandle<()>,
}

impl Worker {
    fn new() -> Worker {
        let thread = thread::spawn(move || {
            println!("start sleep 10 secs ...");
            thread::sleep(Duration::from_secs(10));
        });
        Worker {
            thread: thread,
        }
    }
}

struct ThreadPool {
    workers: Vec<Worker>,
}

impl ThreadPool {
    fn new(size: usize) -> ThreadPool {
        assert!(size > 0);
        let mut workers = Vec::with_capacity(size);
        for _ in 0..size {
            workers.push(Worker::new());
        }

        ThreadPool { workers }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        for worker in &mut self.workers {
            worker.thread.join().unwrap();//報錯,無法編譯,thread也無法實現copy trait
            println!("worker thread finished!");
        }
    }
}

fn main() {
    let _pool = ThreadPool::new(3);
    println!("Hello, world!");
}

上述例子中,實現了一個不完整的執行緒池,在Worker中,有一個欄位為執行緒的控制程式碼。當執行緒池物件drop時,無法使用mut物件中成員的引用(即透過&mut self.workers取出worker,在呼叫worker.thread.join())。為了解決此問題,我們可以將Worker結構體修改如下:

struct Worker {
    // thread: thread::JoinHandle<()>,
    thread: Option<thread::JoinHandle<()>>,
}

完整程式碼為:

use std::thread;
use std::time::Duration;

struct Worker {
    // thread: thread::JoinHandle<()>,
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new() -> Worker {
        let thread = thread::spawn(move || {
            println!("start sleep 10 secs ...");
            thread::sleep(Duration::from_secs(10));
        });
        Worker {
            // thread: thread,
            thread: Some(thread),
        }
    }
}

struct ThreadPool {
    workers: Vec<Worker>,
}

impl ThreadPool {
    fn new(size: usize) -> ThreadPool {
        assert!(size > 0);
        let mut workers = Vec::with_capacity(size);
        for _ in 0..size {
            workers.push(Worker::new());
        }

        ThreadPool { workers }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        for worker in &mut self.workers {
            // worker.thread.join().unwrap();
            // println!("worker thread finished!");

            if let Some(thread) = worker.thread.take() {//此處將thread從Worker的thread欄位的Option中拿出來,使用了“Option型別作為結構體中可借出或者是可載入的欄位”
                thread.join().unwrap();
                println!("worker thread finished!");
            }
        }
    }
}

fn main() {
    let _pool = ThreadPool::new(3);
    println!("Hello, world!");
}

在ThreadPool的drop實現中,透過option的take方法,將thread從worker中移出,然後呼叫join,成功解決問題。

方法

  • is_some

    pub fn is_some(&self) -> bool

    當Option中有值時,返回true。

  • is_none

    pub fn is_none(&self) -> bool

    當Option為None時,返回true。

  • contains

    pub fn contains<U>(&self, x: &U) -> bool
    where
        U: PartialEq<T>, 

    當Some中包含給定的值時,返回true。這個是nightly API。

    //示例
    #![feature(option_result_contains)]
    
    let x: Option<u32> = Some(2);
    assert_eq!(x.contains(&2), true);
    
    let x: Option<u32> = Some(3);
    assert_eq!(x.contains(&2), false);
  • as_ref

    pub fn as_ref(&self) -> Option<&T>

    &Option<T> 轉換為Option<&T>

    //例子
    let text: Option<String> = Some("Hello, world!".to_string());
    
    let text_length: Option<usize> = text.as_ref().map(|s| s.len());
    println!("still can print text: {:?}", text);
  • take

    pub fn take(&mut self) -> Option<T>

    把值從Option中拿出來,留下None。

    let mut x = Some(2);
    let y = x.take();
    assert_eq!(x, None);
    assert_eq!(y, Some(2));
    
    let mut x: Option<u32> = None;
    let y = x.take();
    assert_eq!(x, None);
    assert_eq!(y, None);
  • copied

    pub fn copied(self) -> Option<T>

    Option<&T>得到Option<T>(透過複製來實現)

    let x = 12;
    
    let opt_x = Some(&x);
    assert_eq!(opt_x, Some(&12));
    
    let copied = opt_x.copied();
    assert_eq!(copied, Some(12));
  • cloned

    pub fn cloned(self) -> Option<T>

    Option<&T>得到Option<T>(透過克隆來實現)

    let x = 12;
    
    let opt_x = Some(&x);
    assert_eq!(opt_x, Some(&12));
    
    let cloned = opt_x.cloned();
    assert_eq!(cloned, Some(12));
本作品採用《CC 協議》,轉載必須註明作者和本文連結
令狐一衝

相關文章