右上➚

プログラミングに関するメモをのこしていきます

Rust で Box に包まれた構造体の所有権分解

ちょっとはまったのでメモ

struct A {
    foo: Vec<i32>,
    bar: Vec<bool>,
}

こんな構造体があったとする。 普通、A の所有権を分解して foobar にしたいときは

fn xxx(x: A) -> (Vec<i32>, Vec<bool>) {
    let A { foo, bar } = x;
    (foo, bar)
}

とやれば良い(この例だともっと簡単に書ける気もするけど)

一方、Box<A> から foobar に分解したい場合は話が変わってくる。

fn error1(x: Box<A>) -> (Vec<i32>, Vec<bool>) {
    (x.foo, x.bar)
}

fn error2(x: Box<A>) -> (Vec<i32>, Vec<bool>) {
    let A { foo, bar } = *x;
    (foo, bar)
}

これらは両方共コンパイルできない。 人間から見ると,Box<A>A の所有権を持っているのだから、A -> foo/bar に分解できるなら Box<A> も同様にできる気がする。

実際にはこのようにするとコンパイルが通る。

fn success(x: Box<A>) -> (Vec<i32>, Vec<bool>) {
    let x = *x;
    let A { foo, bar } = x;
    (foo, bar)
}

うーん、エラーになるケースだと Deref トレイトの機能を経由している感じになるのかな? Deref 経由で foo の所有権をとるとその時点で Box<A> の所有権は奪われちゃうから bar の所有権が取れないということなのだと想像した。 success のようなコードが突然出てきたら混乱しそうだ。