rust

what is the different with Option as_ref and as_deref in Rust


Now I am using the rust code snippet like this:

let stackoverflow = format!("{}{}{}","\\social[stackoverflow]{",request.cv_main.stackoverflow.as_deref().unwrap_or_default(),"}\n");

and this is the request cv_main defined:

use serde::{Deserialize, Serialize};

use super::{edu::edu::CvEduResp, work::cv_work_resp::CvWorkResp};

#[derive(Serialize, Deserialize, Default, Clone)]
pub struct CvMainResp {
    pub id: i64,
    pub cv_name: String,
    pub created_time: i64,
    pub updated_time: i64,
    pub user_id: i64,
    pub cv_status: i32,
    pub template_id: i64,
    pub employee_name: Option<String>,
    pub birthday: Option<String>,
    pub phone: Option<String>,
    pub email: Option<String>,
    pub stackoverflow: Option<String>,
    pub github: Option<String>,
    pub blog: Option<String>,
    pub edu: Option<Vec<CvEduResp>>,
    pub work: Option<Vec<CvWorkResp>>,
}

this code works fine, but I am still could not understand why here need to use as_deref(). I have read the article https://www.fpcomplete.com/blog/rust-asref-asderef/, still did not figure out. does there any simple explain the different with as_ref and as_deref?


Solution

  • Option::as_ref() takes an &Option<String> and converts it to Option<&String>. The latter is not the same type as Option<&str>, the difference being that Option<&String> always refers to an actual String, whereas Option<&str> can refer to string data that is just part of a String or that is not stored in a heap-allocated String at all (but in a static constant, for example). For this reason APIs that take strings are encouraged to accept &str or Option<&str> rather than &String or Option<&String>. Fortunately, when you have an Option<&String>, you can always convert it to Option<&str> (but not the other way around).

    To convert Option<&String> returned by as_ref() to Option<&str>, you can call opt.as_ref().map(|s| s.as_str()). String also exposes as_str() by implementing Deref, which is why you can call all str methods on a String. Deref allows the string slice to be accessed through the &*s syntax, so another way to obtain Option<&str> is opt.as_ref().map(|s| &*s). This slightly awkward syntax has the benefit of working in generic code where as_str() is not available. Option::as_deref() is a short-hand for that - called on Option<String>, it will return Option<&str>. Called on Option<Vec<u8>> will return Option<&[u8]>, and so on.

    Finally, while Option<&String> and Option<&str> are functionally similar, they are not exactly the same. In the code that is shown, as_deref() allows the call to .unwrap_or_default(). unwrap_or_default() works on Option<&str> because &str implements Default, where <&str as Default>::default() just returns the reference to a statically allocated "" singleton. On the other hand, &String doesn't implement Default, because it would have to return a reference to a String that outlives it, which is disallowed by the borrow checker.