4

コメントでマークされたエラーメッセージを生成する以下のコードがあります。私はメッセージを理解していると思います: 親を 2 回借用したい: 1 回はその子を見つけるため、もう 1 回は子への引数として (エラー内の可変/不変の単語は関係ありません)。Childを変更しても消えないことを証明する必要がありParentます。しかし、これを行う方法がわかりません。縫い目が無駄になる以外は何でもできるRc<Child>ので、いくつかのライフタイムを追加することでうまくいくことを願っています。

struct Parent {
    used: i32,
    child: Child,
}

struct Child {
    dummy: i32,
}

impl Child { 
    fn use_parent(&mut self, parent: &mut Parent) {
        // use both child and parent
        parent.used += self.dummy;
        self.dummy += 1;
    }
}
fn main() {
    let parent = Parent {
        used: 0,
        child: Child {
            dummy: 1
        }
    };
    //Error: cannot borrow immutable local variable `parent` as mutable
    parent.child.use_parent(&mut parent);
}
4

2 に答える 2

1

エラー内の可変/不変の単語は関係ありません

なぜあなたがそう思うのか私にはわかりません。Rust では可変性が非常に重要です。たとえば、不変データへの複数の参照は同時に許可されていますが、可変データへの参照は一度に 1 つしか許可されていません。

まず、次の可変性を修正する必要がありますparent

let mut parent = // ...

次に、次の行からエラーが発生します。

parent.child.use_parent(&mut parent);

この行を実行すると、暗黙的にミュータブルに and を借りることparentになりchildます。use_parentこれは、 を呼び出すことができるようにするために行われます&mut self

ただし、引数として 2 番目の変更可能な参照も取得しようとしています! 複数のエイリアシング可変参照を持つことが許可されている場合、コンパイラはそれを追跡できず、メモリの安全性の保証を破らないようにすることができないため、これはノーノーです。

行を削除して、self.dummy+=1;変更可能なエイリアスが 1 つだけになるとします。これを機能させることはできますか?

関数シグネチャのいくつかのバリエーションを見てみましょう

fn use_parent(&self, parent: &mut Parent)
// cannot borrow `parent` as mutable because `parent.child` is also borrowed as immutable

fn use_parent(&mut self, parent: &Parent)
// cannot borrow `parent` as immutable because `parent.child` is also borrowed as mutable

fn use_parent(&self, parent: &Parent)
// OK

前に述べたように、何かへの変更可能な参照がある場合、同じもの (変更可能かどうかに関係なく) への他の参照を持つことは許可されません。

また、メソッドの本体が何であるかは問題ではないことに注意してください。Rust は、呼び出された関数の署名のみをチェックして、何かを借用しても安全かどうかを検証します。

では、どのように問題を解決しようとしますか? 最終的に、コンパイラが安全であることを証明するのが非常に難しいことをしようとしています。変更可能なリンクのグラフが必要です。まさにこの親子関係の例があるRcのモジュール ドキュメントを読むことを強くお勧めします。

于 2015-03-03T14:15:04.037 に答える
1

別の理由でエラー メッセージが表示されます。可変でない変数parentがあり、それに を作成しようとして&mutいます。あなたが得ることを修正する

let mut parent = Parent {
    used: 0,
    child: Child {
        dummy: 1
    }
};
parent.child.use_parent(&mut parent);

および対応するエラー

<anon>:31:34: 31:40 error: cannot borrow `parent` as mutable more than once at a time
<anon>:31     parent.child.use_parent(&mut parent);
                                           ^~~~~~
<anon>:31:5: 31:17 note: previous borrow of `parent.child` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `parent.child` until the borrow ends
<anon>:31     parent.child.use_parent(&mut parent);
              ^~~~~~~~~~~~
<anon>:31:41: 31:41 note: previous borrow ends here
<anon>:31     parent.child.use_parent(&mut parent);
                                                 ^

あなたはほぼ正しい結論を導き出しました。

親を変更しても子が消えないことを証明する必要があります

そうではありません。あなたは子供に2つ&mutまたは1つと1つを決して持たないことを証明する必要があります. 親に がある場合は、それを使用して子に を取得できます。したがって、親に aを、子に a を指定すると、子に 2 つを指定できます。&mut&&mut&mut&mut&mut&mut


私が見る唯一の解決策は、use関数を型に移動してthroughParentにアクセスすることです。childself

impl Parent { 
    fn use_parent(&mut self) {
        // use both child and parent
        self.used += self.child.dummy;
        self.child.dummy += 1;
    }
}

コメントへの対応:

残念ながら、解決策はこの単純化された問題には適用されますが、実際の問題には適用されません。親には、深くネストされた孫を持つ可能性のある子のベクトルがあります。私はself.childとは言えません

ベクトルを変更してはならない (変更できない、Rust が保護する) ため、子への参照が無効になるため、それらの部分を必要な関数に渡すことができますが、直接の親である部分はどれも渡せません。子供の。

impl Child { 
    fn use_parent(&mut self, used: &mut i32) {
        // use both child and parent
        *used += self.dummy;
        self.dummy += 1;
    }
}

fn main() {
    let mut parent = Parent {
        used: 0,
        child: Child {
            dummy: 1
        }
    };
    // although both point to elements of the same structure
    // it is guaranteed at compile-time that they point to
    // non-overlapping parts
    let child = &mut parent.child;
    let used = &mut parent.used;
    child.use_parent(used);
}

残念ながら、 のパラメータが同じオブジェクトuse_parentの一部を指していることを証明する方法がわかりません。Parent多分それは生涯でできるかもしれませんが、私にはわかりませんが、私はそれに非常に興味があります. 注:Rc同じ問題があります。

于 2015-03-03T14:22:41.087 に答える