所有権と借用について

Rustの所有権と借用の概念について、おのれなりの理解をまとめてみました。ほぼ個人メモです。

##バージョン

```
$ rustc --version
rustc 1.4.0 (8ab8581f6 2015-10-27)
```

##所有権の移動

プリミティブ型の代入式は、所有権の移動が発生しない。

```rust:
let a = 100;
let b = a;
println!("a = {}", a);
// => a = 100
```

所有権の移動が発生するケースとして、構造体を例として考えてみる。以下例では、`a`から`b`に所有権を移動した後に`a`を参照したが、`a`はすでに所有権を失っているため、コンパイルエラーが発生した。

```rust:
struct Point {
    x :i32,
    y :i32,
}
fn main()
{
    let a = Point{x:100, y:200};
    let b = a;
    println!("a.x = {}, a.y = {}", a.x, a.y);
// => error: use of moved value: `a.x` [E0382]
}
```

同様に、関数の引数として渡すことも所有権の移動が発生するため、その後の使用はコンパイルエラーとなる。

```rust:
struct Point {
    x :i32,
    y :i32,
}
fn f(x: Point)
{
}
fn main()
{
    let a = Point{x:100, y:200};
    f(a);
    print!("a.x = {}, a.y = {}", a.x, a.y);
// =>  error: use of moved value: `a.x` [E0382]
}
```

じゃあ、構造体のコピーができないじゃん！と思ったが、
`let b = Point{..a};`
と書けばよいみたい。

所有権の移動に関して許されるのは「Ownerが、貸与中でないオブジェクトの所有権を移動すること」だけである。Ownerが、貸与中オブジェクトの所有権を移動することはできないし、また、Borrowerが、借用中オブジェクトの所有権を勝手に移動することもできない。

```rust:
struct Point {
    x :i32,
    y :i32,
}
fn main()
{
    let a = Point{x:100, y:200};
    {
        let b = &a;
        let c = a;  // NG
        // => error: cannot move out of `a` because it is borrowed
    } 
    {
        let b = &mut a;
        let c = *b; // NG
        // => error: cannot move out of borrowed content
    }
    let d = a;  // OK
```

## 所有権の返却

所有権を移動した場合、借用とは異なり、新しいOwnerが死んでも所有権は以前のOwnerには戻ってこない。ただし、所有権を取り戻すことはできる。

以下のコードは、このままではコンパイルエラーとなる。式文（1）をコメントアウトし、所有権を戻す式文（2）を有効にすれば、コンパイルは通る。

```rust:
struct Point {
    x :i32,
    y :i32,
}

fn f(x :Point) -> Point { x }

fn main()
{
    let mut a = Point{x:100, y:200};
    f(a);  // （1）
//    a = f(a);  // （2）
    a;
    // => (式文(1)が有効の場合)error: use of moved value: `a`
}
```

##借用（immutableな場合）

immutableなオブジェクトであれば、複数の借用者に貸出できる。immutable借用中のimmutableな又貸しは許されるが、mutableな又貸しは許されない。

```rust:
fn f(x: &Point)
{
}
fn main()
{
    let a = Point{x:100, y:200};

    // Owner:Borrowerが1:nの関係でもOK
    let b = &a; 
    let c = &a; 
    f(&a);

    // immutableな又貸しはOK
    let d = &*b; 

    // mutableな又貸しは許されない
    let d = &mut *b;  // NG
    //error: cannot borrow immutable borrowed content `*b` as mutable
}
```

リテラルからの借用も可能。リテラルにも、ストレージ上に領域が割り当てられていることが分かる。

```rust:
let x = &100;
println!("{:p}:x = {:p} => {}", &x, x, *x);
// => 0xbfad9974:x = 0xb7705084 => 100

let x = &"hoge";
println!("{:p}:x = {:p} => {}", &x, x, *x);
// => 0xbfad98fc:x = 0xb7713748 => hoge
```

Ownerのlifetimeは、Borrowerのlifetimeを包含しなければならない。OwnerがBorrowerより先に死んではならない（mutableな場合も同様）。

```rust:
let b = {
    let a = 100;
    &a  // NG
    // => error: `a` does not live long enough
};
```

##借用（mutableな場合）

オブジェクトをmutable貸与するには、Ownerをmutableとし、かつ、貸出をmutableとしなければならない（Borrower自体がmutableである必要は無い）。

```rust:
let mut a = 100;
let b = &mut a;
*b = 200;  // OK
```

Borrower自体がmutableであるべきなのは、Borrower自体の借用元Ownerを変更する場合である。

```rust:
let a = 100;
let b = 200;

let mut c = &a;
println!("c = {}", *c);  // => c = 100
c = &b;
println!("c = {}", *c);  // => c = 200
```

mutableなオブジェクトについて、immutableな貸与をした場合、貸与中オブジェクトへの書き込みはOwnerであっても許されない。読み取りは可能。これは、immutableなオブジェクトの場合と同様の挙動となる。

```rust:
let mut a = 100;
{   
    let x = &a; 
    a = 200;  // write NG
// => error: cannot assign to `x` because it is borrowed
    a;  // read OK
}   
a = 200;  // write OK
```

mutableな又貸しは許される。Ownerが書き込みを許可して貸与した以上、書き込む主体が誰なのかはOwnerは気にしない。

```rust:
let mut a = 100;
{
    let b = &mut a;
    {
        let c = &mut *b;  // OK
        *c = 200;  // OK
    }
    *b = 300;  // OK
}
a = 400;  // OK
```

mutableなオブジェクトについて、immutableな貸与をした先で又貸しをした場合、その挙動はimmutableなオブジェクトを又貸しした場合と同様の挙動となる。

つまり、オブジェクトのimmutable/mutableは、immutable貸与の挙動に影響しない。

```rust:
fn main()
{
    let a = 100;
    {   
        let b = &a; 
        {   
            let c = &*b;
        }   
    }   
    let mut a = 100;
    {   
        let b = &a; 
        {   
            let c = &*b;
        }   
    }   
}
```

Borrower自体の借用元Ownerを変更しても、Borrowerが生きている限り、以前のOwnerによる使用（読み取り含む）は許されない。

```rust:
let mut a = 100;
let mut b = 200;
{
    let mut c = &mut a;
    c = &mut b;
    a;  // NG
    // => error: cannot use `a` because it was mutably borrowed
    b;  // NG
    // => error: cannot use `b` because it was mutably borrowed
    c = 300;  // OK
}
a = 400;  // OK
b = 500;  // OK
```

mutable貸与中のオブジェクトは、Ownerによる一切の使用（読み取り、書き込み、mutable貸与、immutable貸与、所有権の移動）が許されない。

```rust:
struct Point {
    x :i32,
    y :i32,
}
fn main()
{
    let mut a = Point{ x:100, y:200 };
    {
        let b = &mut a;
        a.x;  // NG
        // =>error: cannot use `a.x` because it was mutably borrowed
        a.x = 200;  // NG
        // => error: cannot assign to `a.x` because it is borrowed
        let c = &mut a;  // NG
        // => error: cannot borrow `a` as mutable more than once at a time
        let d = &a;  // NG
        // => error: cannot borrow `a` as immutable because it is also borrowed as mutable
        let e = a;  // NG
        // => error: cannot move out of `a` because it is borrowed
    }
}
```

上の制約より、次の制約が帰結する。すなわち、一つのオブジェクトをmutable borrowing中に貸与できるのは、（immutable貸与であろうが、mutable貸与であろうが）同時に高々1回まで。以前のBorrowerが死んではじめて、新たなBorrowingが可能となる。

```rust:
let mut a = 100;
{   
    {   
        let b = &mut a;
        let c = &mut a;  // NG
// => error: cannot borrow `a` as mutable more than once at a time

    }   
    let c = &mut a;  // OK
    *c = 200;  // OK
}   
a = 300;  // OK
```

Borrowerが、Borrower自体の所有権を移動したとき、移動先が新たなBorrowerとなる。また、（Borrower自体の）所有権の移動により、Borrowerがその時点で持っていた借用は、（借用がmutableであることも含めて）新たなBorrowerに委譲される。

ただし、借用が委譲されてもImmutable Borrowing中であることには変わりないので、委譲のタイミングではOwnerにオブジェクトは返却されない。返却されるのは、新たなBorrowerが死んだ瞬間である。

```rust:
// a --(借用)--> b --(b自体の所有権)--> c は
// a --(借用)--> c　と等価となる。
let mut a = 100;
{   
    let b = &mut a;
    let c = b;
    a;  // NG
    // => cannot use `a` because it was mutably borrowed
    *b;  // NG
    // =>  error: use of moved value: `b`
    *c = 200;  // OK
}
a;  // OK
a = 300;  // OK
```

貸与した所有権を明示的に取り戻すことはできない。やはり、Borrowerが死ぬのを待つしかない。

```rust:
let mut a = 100;
{   
    let b = &mut a;
    a = *b;  // NG
    // => error: cannot assign to `a` because it is borrowed
}   
a = 200;  // OK
```

構造体の複数のメンバ変数を、個別にmutable貸与することは可能。ただし、メンバ変数をmutable貸与中に、それが属する構造体変数をimmutable/mutable貸与することや、構造体変数をmutable貸与中に、そのメンバ変数をimmutable/mutable貸与することはできない。

```rust:
struct Point {
    x :i32,
    y :i32,
}
fn main()
{
    let mut a = Point{x:100, y:200};
    {   
        let b = &mut a.x; // OK
        let c = &mut a.y; // OK
        let d = &a; // NG
        // => error: cannot borrow `a` as immutable because `a.y` is also borrowed as mutable
    }   
}
```

##まとめると

借用中オブジェクトへのアクセス可否について、表にまとめてみました。行見出し（縦）がオブジェクトのimmutabe/mutableを示し、列見出し（横）が借用時のimmutable/mutable指定を示します。
（RO … Read Only　RW … Read Write）

||Immutable<BR>Borrowing|Mutable<BR>Borrowing|
|:---|:---|:---|
|**Immutable<BR>Owner**|Owner : RO<BR>Borrower : RO<BR>Immutable Subletting : OK<BR>Mutable Subletting : × Forbidden<BR>|× Forbidden|
|**Mutable<BR>Owner**|Same as above|Owner's access: × Forbidden<BR>Borrower : RW<BR>Immutable Subletting : OK<BR>Mutable Subletting : OK|

こうしてみると意外と単純で、

* immutableなオブジェクトは、immutableな借用のみ可能である。
* mutableなオブジェクトは、immutable/mutableいずれの借用も可能である。
* immutableな借用は、オブジェクトのimmutable/mutableに関係なく、誰にとってもRead Onlyである。
* immutableで借用しているオブジェクトを、immutableで又貸しすることは可能である。ただし、mutableな又貸しはできない。
* mutable借用中の、immutableまたはmutableな又貸しは可能である。
* mutableなオブジェクトがmutable借用された場合、BorrowerによるRead Write、mutable貸与が可能である。
* Borrowerが、借用中オブジェクトの所有権を移動することはできない。
* 所有権の移動は、貸出中でない時にOwnerによって可能。
* mutable借用中のオブジェクトに対する、Ownerからのアクセスは一切不可能。

ということになります。

##さらにまとめると

* 所有権の移動に関して可能なのは、「Ownerが、貸与中でないObjectの所有権を移動すること」のみ。
* immutablly borrowed objectは、write以外のすべての操作が可能である。
* mutablly borrowed objectは、Ownerによるすべての操作が禁止され、Borrowerによるすべての操作が許可される。

すべての操作とは、Read、Write、Lendingを指す。