2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rustで自身をフィールドに持つ親の構造体を可変参照する

Posted at

以下のような構造体を考えます。

#[derive(Debug)]
struct Parent {
    name: String,
    children: Vec<Child>,
}

#[derive(Debug)]
struct Child {
    name: String,
}

impl Child {
    fn update(&mut self, parent: &mut Parent) {
        self.name = parent.name.clone();// 親の構造体のフィールドを可変参照する(可変参照する必要は無いが便宜上)
    }
}

この構造体でupdate関連関数を呼び出すとき、自身を含むparentを引数に渡すときには注意が必要です。

まず実体にします。

let mut parent = Parent {
    name: "parent".to_string(),
    children: vec![Child {
        name: "child".to_string(),
    }],
};

ここで、以下のように自身を含む構造体をupdateに渡すと、可変参照が2回行われ所有権の規則に反します。

for child in &mut parent.children {
    child.update(&mut parent);// cannot borrow `parent` as mutable more than once at a time
}

そのため、可変参照を2つ以上取らないようにするため、構造体から自身を退避した後に、戻す必要があります。

// std::mem::takeで奪うと、自身を含まなくなるので親を可変参照できる
let mut children = std::mem::take(&mut parent.children);

for child in &mut children {
    child.update(&mut parent);
}
        
// 奪ったので戻す
parent.children = children;

最終的なコードは以下のようになります。

#[derive(Debug)]
struct Parent {
    name: String,
    children: Vec<Child>,
}

#[derive(Debug)]
struct Child {
    name: String,
}

impl Child {
    fn update(&mut self, parent: &mut Parent) {
        self.name = parent.name.clone();
    }
}

fn main() {
    let mut parent = Parent {
        name: "parent".to_string(),
        children: vec![Child {
            name: "child".to_string(),
        }],
    };

        
    // std::mem::takeで奪うと、自身を含まなくなるので親を可変参照できる
    let mut children = std::mem::take(&mut parent.children);
    for child in &mut children {
        child.update(&mut parent);
    }
    
    // 奪ったので戻す
    parent.children = children;

    println!("{:?}", parent);

}

これを実行するとParent { name: "parent", children: [Child { name: "parent" }] }が結果になります。

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?