13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RustのOptionの as_ref() と unwrap() と as_mut() を理解する

Last updated at Posted at 2022-01-25

概要

Rc::as_ref() の入れ所がよく分からなくなってきたので、作ったもの。

環境

  • Ubuntu 18.04 LTS
  • rust 1.58

解説

as_ref()を使わない場合

例1: sを消費して中身を取り出す

fn main() {
    let s: Option<String> = Some(String::from("hello"));
    let t: String = s.unwrap().push_str(" world!");
    assert_eq!(t, "hello world!");
}

例2: unwrap() は消費する

次の例は、unwrap で所有権の移動が起こるので、コンパイルエラーとなる。

fn main() {
    let s = Some(String::from("hello"));
    if s.unwrap().len() == 5 {  // move
        let mut t = s.unwrap();
        //          ^ value used here after move
        t.push_str(" world!");
        assert_eq!(t, "hello world!");
    }
}

例3: as_ref()を使う

Option::as_ref() は、&Option<T>Option<&T> に変換します。
&String のように借用するのであれば、消費はされません。

  • s.as_ref(): Some("hello") → Some(&"hello")
  • s.as_ref().unwrap(): Some(&"hello") → &"hello"
  • s.as_ref().unwrap().len(): &"hello" → &"hello".len()

※ String は省略しています

fn main() {
    let s = Some(String::from("hello"));
    if s.as_ref().unwrap().len() == 5 {
        let mut t = s.unwrap();
        t.push_str(" world!");
        assert_eq!(t, "hello world!");
    }
}

応用例: as_mut()

  • self.msg.as_mut() の部分が self.msg の場合に失敗するのは上で説明した通り、move されるからです
  • self.msg.as_ref() では、可変の借用ではないので String::push_str() は使えません
  • Option::as_mut() は mut Option(T) → Option(&mut T) に置き換えます
  • &mut String なら、push_str() は使えます。
struct Msg {
    msg: Option<String>,
}

impl Msg {
    pub fn push_str_in_option(&mut self, a: &str) {
        if let Some(msg) = self.msg.as_mut() {
            msg.push_str(a);
        }
    }
}

fn main() {
    let mut s = Msg { msg: Some(String::from("hello")) };
    s.push_str_in_option(" world!");
    assert_eq!(s.msg, Some(String::from("hello world!")));

    let mut s = Msg { msg: None };
    s.push_str_in_option(" world!");
    assert_eq!(s.msg, None);
}

次のようにも書ける。
Option::map(f)Option(&T)Option(f(&T)) とできる。

//...

impl Msg {
    pub fn push_str_in_option(&mut self, a: &str) {
        self.msg.as_mut().map(|s| s.push_str(a));
    }
}

//...
13
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?