與 Rust 編譯器的鬥爭 - 1

我們來看第一個案例,考慮下面的函數,它接收一個借用的 Option 作爲輸入,如果字符串爲空,則打印爲空。

fn parse_option(opt: &Option<String>) {
    println!("{}", opt.unwrap_or("empty".to_owned()));
}

這個簡單的單行函數會導致編譯錯誤:

error[E0507]: cannot move out of `*opt` which is behind a shared reference
 --> <source>:2:20
  |
2 |     println!("{}", opt.unwrap_or("empty".to_owned()));
  |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `*opt` has type `Option<String>`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.
Compiler returned: 1

讓我們看看發生了什麼。首先,參數 opt 的類型是 & Option,也就是說,它是不可變借用的 Option,這意味着我們既不能移出它,也不能修改它。現在,讓我們看一下 Option::unwrap_or() 的方法簽名。

pub fn unwrap_or(self, default: T) -> T

如果你檢查 Option 的文檔,你會發現一個方法 Option::as_deref(),它的簽名如下:

pub fn as_deref(&self) -> Option<&<T as Deref>::Target>

該方法基本上將 (不修改 / 移動)Option 或 & Option 轉換爲 Option<&T>,這正是我們想要的。該方法的第一個參數是 & self,因此我們可以在 & Option 類型上調用該方法。從技術上講,該方法將輸出另一個 Option 實例,該實例具有對所包含值的引用,我們現在可以調用 unwrap_or() 方法。因此,下面是修復後的代碼:

fn parse_option(opt: &Option<String>) {
    println!("{}", opt.as_deref().unwrap_or("empty"));
}

首先,我們在調用 unwrap_or() 方法之前調用 as_deref()。第二,我們提供了另一個字符串 empty 作爲 & str 類型而不是 string 類型。希望這個例子能幫助你瞭解 Rust 編譯器。

as_ref() 和 as_deref() 看起來非常相似,那麼 as_ref() 是否也可以工作。它們的關鍵區別在於 as_ref() 是字面引用,而 as_deref() 是對 Deref::Target 的引用。在本例中,該選項包含的值類型是 String。在這種情況下,我們得到:

opt.as_ref(): Option<&String>
opt.as_deref(): Option<&str>

如果我們要使用 as_ref(),我們還需要確保爲 unwrap_or() 函數提供 & String 類型,這是可行的,但不會像簡單地使用 as_deref() 那樣簡潔。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/oN07Qv-RNNpB2ao5WYWGVA