Mutable referenceからは(partial) moveできない

[Rust bookのChapter 17](https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.html#requesting-a-review-of-the-post-changes-its-state)に、StateをなぜOptionに入れるかの理由が書いてある。なんとなく分かった気分になっていたが、後になって理解が甘かったことに気付いたのでメモ。

## 所有しているstructからはpartial moveできる

[Rust by example](https://doc.rust-lang.org/beta/rust-by-example/scope/move/partial_move.html)にあるように、structの持っている変数の一部をmoveすることができる。その後で元のstructを使おうとすると所有権のエラーが出る（Copy traitが実装されている場合を除く）。
ただし、moveされていない変数はそのまま使うことができる。

```Rust
#[derive(Debug)]
struct Test {
    str1: String,
    str2: String,
}

fn main() {
    let t = Test {
        str1: String::from("str1"),
        str2: String::from("str2"),
    };

    println!("{:?}", t); // Test { str1: "str1", str2: "str2" }

    let s = Test {
        str1: String::from("new_str1"),
        str2: t.str2,
    };

    println!("{:?}", s); // Test { str1: "new_str1", str2: "str2" }
    // println!("{:?}", t); // <-- error!
    println!("{}", t.str1); // str1
}
```

Moveされた変数に新しく値をbindingしなおすこともできる。

```Rust
fn main() {
    let mut t = Test { .. };
    // -- snip --
    t.str2 = String::from("new_str2");

    println!("{:?}", s); // Test { str1: "new_str1", str2: "str2" }
    println!("{:?}", t); // Test { str1: "str1", str2: "new_str2" }
    println!("{}", t.str1); // str1
}
```

## Mutable referenceからは(partial) moveできない

一方、mutable referenceからはこのようなことはできない（できたら所有権のルールが壊れるわけで）。

```Rust
fn main() {
    let mut t = Test {
        str1: String::from("str1"),
        str2: String::from("str2"),
    };
    let t_ref_mut = &mut t;

    println!("{:?}", t_ref_mut); // Test { str1: "str1", str2: "str2" }

    let s = Test {
        str1: String::from("new_str1"),
        str2: t_ref_mut.str2, // <-- error!
    };

    t.str2 = String::from("new_str2");
}
```

もっとダイレクトに

```Rust
    let s = *t_ref_mut;
```

とするのも、もちろん上手くいかない。
（なお、ここでmutable referenceを使う必要はなく、単にreferenceでも同じ話なのだが、次の節との整合性でmutableにしている。）

この例ではStringにはClone traitが実装されているので、一回別の値に退避させておくことはできる。

```Rust
    let tmp = t_ref_mut.str2.clone();

    let s = Test {
        str1: String::from("new_str1"),
        str2: tmp,
    };

    t.str2 = String::from("new_str2");

    println!("{:?} {:?}", t, s);
```

ただ、Cloneが実装されていない型の変数を持つようなstructだと、Clone traitが実装できなかったりする。その場合にはこの方法は使えない。

## Optionを使って実現する

Optionで囲うことで、Cloneが実装できないstructに対してもpartial moveっぽいものが実現できる。
つまり、変数に対してOption::take()を呼び出すことで、structのmutable referenceから所有権付きで値を取り出すことができる。

```Rust
#[derive(Debug)]
struct Test {
    str1: Option<String>,
    str2: Option<String>,
}

fn make_s(t_ref_mut: &mut Test) -> Test {
    let tmp = t_ref_mut.str2.take();

    Test {
        str1: Some(String::from("new_str1")),
        str2: tmp,
    }
}

fn main() {
    let mut t = Test {
        str1: Some(String::from("str1")),
        str2: Some(String::from("str2")),
    };

    println!("{:?}", t); // Test { str1: Some("str1"), str2: Some("str2") }

    let s = make_s(&mut t);
    t.str2 = Some(String::from("new_str2"));

    println!("{:?}", s); // Test { str1: Some("new_str1"), str2: Some("str2") }
    println!("{:?}", t); // Test { str1: Some("str1"), str2: Some("new_str2") }
}
```

関数にする意味はここでは無いが、同様にすればstructのmethodの実装に使うことができる。

## Optionを使わずにできないの？

ここで、なぜOptionを使えばこんなことができるのかが疑問になる。Optionでできるなら元のStringのままでもできそうな気もしてくる。

調べてみると、どうやらOptionそのものに本質的な意味があるわけではないようだ。
Rustのドキュメントで[Option::takeの実装](https://doc.rust-lang.org/core/option/enum.Option.html#method.take)を見ると、[mem::take](https://doc.rust-lang.org/core/mem/fn.take.html)というものが呼び出されている。これはDefault traitが実装されている型に対して動く。

StringはDefault traitが実装されているので、先程までのコードは次のように書くことができる。

```Rust
use std::mem;

#[derive(Debug)]
struct Test {
    str1: String,
    str2: String,
}

fn make_s(t_ref_mut: &mut Test) -> Test {
    let tmp = mem::take(&mut t_ref_mut.str2);

    Test {
        str1: String::from("new_str1"),
        str2: tmp,
    }
}

fn main() {
    let mut t = Test {
        str1: String::from("str1"),
        str2: String::from("str2"),
    };

    let s = make_s(&mut t);

    // --snip--
}
```

当然、OptionにもDefault traitが実装されている（default()はNoneを返す）。
Defaultが実装されている型なら直接mem::takeを呼べるし、Defaultが実装されていない型でもOptionで囲ってやることでOption::takeが使えるということである。

ところで、mem::takeはどう実現されているのだろう？
内部的には（いくつかの関数を経た後で）ptr::swap_nonoverlapping_oneというunsafeな関数が呼び出され、raw pointerを使っていろいろしているらしい。
多分、safeなRustでtake的な動作を（Cloneなどが実装されていない型に対しても）実現するのは難しいんだろうなーという気がする。

---
追記：[知っていないと中々思いつかないrustのイディオム](https://qiita.com/knknkn1162/items/1d190880efffe3578d92)ではtakeイディオムと呼ばれています。