関数をデフォルトのトレイトメソッドに移動すると、借用エラーが発生するのはなぜですか?

一生立ち往生

Foo要素のコレクションを含む構造体がある場合:

#[derive(Debug)]
struct Foo {
    bar: Vec<i8>,
}

の一部をカプセル化することを目的とした可変ビューオブジェクトを作成しましたFoo

#[derive(Debug)]
struct View<'a> {
    foo: &'a mut Foo,
}

impl<'a> View<'a> {
    fn iter(&'a self) -> std::slice::Iter<'a, i8> {
        self.foo.bar.iter()
    }

    fn iter_mut(&'a mut self) -> std::slice::IterMut<'a, i8> {
        self.foo.bar.iter_mut()
    }

    fn mutate(&'a mut self) {
        let mut vector: Vec<i8> = vec![];
        for value in self.iter().take(1).cloned() {
            vector.push(value);
        }
        for value in self.iter_mut() {
            *value = 0;
        }
    }
}

上記のView構造体は意図したとおりに機能し、次のコードが出力されFoo { bar: [0, 0, 0] }ます。

fn main() {
    let mut foo = Foo { bar: vec![0, 1, 2] };
    let mut view = View { foo: &mut foo };
    view.mutate();
    println!("{:?}", foo);
}

ただし、さまざまな種類のビューが可能である必要があります。Fooマトリックスの場合、ビューは行、列、または部分行列である可能性があります。したがってView、構造体によって実装されたトレイトとしてを書き直し、mutateデフォルトの実装を与えました。

trait AbstractView<'a> {
    type Iterator: Iterator<Item = &'a i8>;
    type IteratorMut: Iterator<Item = &'a mut i8>;

    fn iter(&'a self) -> Self::Iterator;
    fn iter_mut(&'a mut self) -> Self::IteratorMut;

    fn mutate(&'a mut self) {
        let mut vector: Vec<i8> = vec![];
        for value in self.iter().take(1).cloned() {
            vector.push(value);
        }
        for value in self.iter_mut() {
            *value = vector[0];
        }
    }
}

#[derive(Debug)]
struct View<'a> {
    foo: &'a mut Foo,
}

impl<'a> AbstractView<'a> for View<'a> {
    type Iterator = std::slice::Iter<'a, i8>;
    type IteratorMut = std::slice::IterMut<'a, i8>;

    fn iter(&'a self) -> Self::Iterator {
        self.foo.bar.iter()
    }

    fn iter_mut(&'a mut self) -> Self::IteratorMut {
        self.foo.bar.iter_mut()
    }
}

このコードは正常にコンパイルされません。rustcはiter_mutinの呼び出しについて文句を言いますmutate

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:18:22
   |
6  | trait AbstractView<'a> {
   |                    -- lifetime `'a` defined here
...
15 |         for value in self.iter().take(1).cloned() {
   |                      -----------
   |                      |
   |                      immutable borrow occurs here
   |                      argument requires that `*self` is borrowed for `'a`
...
18 |         for value in self.iter_mut() {
   |                      ^^^^^^^^^^^^^^^ mutable borrow occurs here

mutateトレイトにデフォルトのメソッドとして実装すると、ボローチェッカーとは異なる動作のように見えるのはなぜですか?この特性を機能させるにはどうすればよいですか?

特性のない例。

特性の例。

rustcバージョン1.43.1を使用します。

スカペラ

それは、形質ベースのバージョンが作業をしない理由を伝えるのは簡単だが、元はなぜ難しいと言って仕事を。

それはすべて一生に一度です。トレイトベースのバージョンの場合、'aどこにでも1つのライフタイムしかありませんself.iter()またはを呼び出すself.iter_mut()と、借用は同じ存続期間続きます。つまり、両方を呼び出すことはできません。両方を呼び出すと、不変と可変の借用の有効期間が同じになるため、同時に存在します。


これは、なぜ非特性バージョンが機能するのかという疑問を提起します。まったく同じことをしませんか?答えは、タイプとの分散にありますジェネリック型の分散があれば、どのようにあるに強制変換することができたとき関連しています。std::slice::Iter<'a, T>std::slice::IterMut<'a, T>T<'a>T<'a>T<'b>'a'b

多くの型では、この関係は共変です。'a'b(書かれた'a: 'bよりも長い場合T<'a>、型の値を型の値に強制変換できますT<'b>他のいくつかのタイプの場合、関係は反変です。の場合'a: 'b、をT<'b>強制することができますT<'a>(この例はですFn(&'a T))。最後に、一部のタイプは不変であるため、強制は発生しません。

std::slice::Iter<'a, T>生涯で共変'aです。場合'aよりも長い'b、我々は短い生涯に強制することができます。それはまさにあなたのコードで起こっていることです。を呼び出すとself.iter().take(1).cloned()self.iter()実際にはより短い値に強制変換されるstd::slice::Iter<'b, i8>ため、後で変更可能な借用が発生する可能性があります。

fn mutate(&'a mut self) {
    let mut vector: Vec<i8> = vec![];
    // let iter = self.iter(); // works
    let mut iter: std::slice::Iter<'a, i8> = self.iter(); // doesn't work!
    for value in iter.take(1).cloned() {
        vector.push(value);
    }
    for value in self.iter_mut() {
        *value = vector[0];
    }
}

上記のコードを使用すると、特性ベースのコードと同様のエラーが発生します。

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:27:22
   |
11 | impl<'a> View<'a> {
   |      -- lifetime `'a` defined here
...
23 |         let iter: std::slice::Iter<'a, i8> = self.iter(); // doesn't work!
   |                   ------------------------   ---- immutable borrow occurs here
   |                   |
   |                   type annotation requires that `*self` is borrowed for `'a`
...
27 |         for value in self.iter_mut() {
   |                      ^^^^^^^^^^^^^^^ mutable borrow occurs here

ちなみに、その寿命std::slice::IterMut<'a, T>不変です。これは、一般に、可変参照は健全であるために不変でなければならないためです。つまり、可変ボローと不変ボローの順序を入れ替えると、非トレイトバージョンでもエラーが発生します。

fn mutate(&'a mut self) {
    let mut vector: Vec<i8> = vec![];
    for value in self.iter_mut() {
        // This would panic if it compiled, of course
        *value = vector[0];
    }
    for value in self.iter().take(1).cloned() {
        vector.push(value);
    }
}

(遊び場)


ので、形質ベースのバージョンでは、仕事をしないようにself.iter()、あまりにも長い間、最後に借りを必要とし、それが短いボローに強制することはできません。実際、物事がどのように書かれているかを考えると、借り入れを短くすることは意味がないかもしれません。Self::Iterその特定のライフタイムに対してのみ定義される場合があります。

それで、これを書くための理想的な方法は何ですか?1つの方法は、の実装をのmutate各実装に配置することですAbstractView具象型Iterを使用する場合IterMut、コンパイラーは、共分散を使用して寿命を短くできることを認識しています。

より多くの原則に基づいた解決策を作ることであろうSelf::IterSelf::IterMut、必要に応じて借りを短縮することができるように生涯におけるジェネリック。このようなジェネリック関連の型はまだ可能ではありません。

夜間コンパイラでは、これを行うことができますが、コンパイラが正しく警告しているように、ジェネリック関連の型はまだ完成しておらず、コンパイラのクラッシュやバグを引き起こす可能性があります。

#![feature(generic_associated_types)]

#[derive(Debug)]
struct Foo {
    bar: Vec<i8>,
}

trait AbstractView {
    type Iterator<'b>: Iterator<Item = &'b i8>;
    type IteratorMut<'b>: Iterator<Item = &'b mut i8>;

    // Eventually, these lifetimes should be elided
    // But it doesn't seem that that's implemented yet
    fn iter<'a>(&'a self) -> Self::Iterator<'a>;
    fn iter_mut<'a>(&'a mut self) -> Self::IteratorMut<'a>;

    fn mutate(&mut self) {
        let mut vector: Vec<i8> = vec![];
        for value in self.iter().take(1).cloned() {
            vector.push(value);
        }
        for value in self.iter_mut() {
            *value = vector[0];
        }
    }
}

#[derive(Debug)]
struct View<'a> {
    foo: &'a mut Foo,
}

impl<'a> AbstractView for View<'a> {
    type Iterator<'b> = std::slice::Iter<'b, i8>;
    type IteratorMut<'b> = std::slice::IterMut<'b, i8>;

    fn iter<'b>(&'b self) -> Self::Iterator<'b> {
        self.foo.bar.iter()
    }

    fn iter_mut<'b>(&'b mut self) -> Self::IteratorMut<'b> {
        self.foo.bar.iter_mut()
    }
}

fn main() {
    let mut foo = Foo { bar: vec![0, 1, 2] };
    let mut view = View { foo: &mut foo };
    view.mutate();
    println!("{:?}", foo);
}

(遊び場)

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Dieselのトレイトを使用して関数をトレイトメソッドに書き換えるときに、「要件を評価するオーバーフロー」が発生するのはなぜですか?

分類Dev

Goのselectステートメントの外に条件を移動すると、このデッドロックが発生するのはなぜですか

分類Dev

postgresqlテーブルを作成するときに「複数のデフォルト値」エラーが発生するのはなぜですか?

分類Dev

定義する前にクラスのオブジェクトを宣言すると、フレンドクラスではエラーが発生するが、フレンド関数ではエラーが発生しないのはなぜですか

分類Dev

子構造のメソッドの結果を返すときに借用エラーが発生するのはなぜですか?

分類Dev

範囲関数を使用してリストにデータを入力すると、%dで印刷するとリストのフォーマットエラーが発生するのはなぜですか?

分類Dev

c ++:テンプレート関数のすべての型パラメーターを指定するとエラーが発生するのに、パラメーターを省略すると問題が発生するのはなぜですか?

分類Dev

デフォルトのメソッドパラメータをC#のコンパイル時定数にする必要があるのはなぜですか

分類Dev

アプリディレクトリにgulp-sassをインストールするときにエラーが発生するのはなぜですか?

分類Dev

定数を使用すると未定義のローカル変数またはメソッドエラーが発生するのに、メソッドを使用するとエラーが発生しないのはなぜですか?

分類Dev

シングルトンクラスのQtメッセージハンドラーメンバー関数を呼び出すとエラーが発生するのはなぜですか:引数リストがありませんか?

分類Dev

data.table行フィルタリングが、エラーを発生させることなく、関数内の欠落している引数をサイレントに受け入れることができるのはなぜですか?

分類Dev

dpkginfoディレクトリのext4でファイルを移動または削除するときにエラーが発生しました

分類Dev

try/except recursive(?) 関数でトレースバック エラーが発生するのはなぜですか?

分類Dev

Ubuntuサーバーのnodejsでディレクトリを動的に作成しているときにエラーが発生するのはなぜですか?

分類Dev

プログラムでメソッドスタブを実装するときに、IntelliJがデフォルトで各メソッドをオーバーライドするのはなぜですか?

分類Dev

ファイルをコミットするときにLibgit2によってエラー「NoMemory」が発生するのはなぜですか?

分類Dev

ocaml-cohttp Client.postメソッドでHTTPSサーバーをリクエストするときにHANDSHAKE_FAILUREをデバッグする方法は?(そして、なぜこのエラーが発生するのですか?)

分類Dev

Pythonにフォーマット関数とフォーマットメソッドがあるのはなぜですか

分類Dev

デフォルトのケースとラムダ関数でswitchステートメントを使用するとgccエラーが発生します

分類Dev

unordered_mapにemplaceメソッドを使用すると、コンパイルエラーが発生するのはなぜですか?

分類Dev

デフォルトのパラメータ値を追加すると、引数を変更するときの動作が変わるのはなぜですか?

分類Dev

コードをコンパイルしようとすると、あいまいなメソッドエラーが発生するのはなぜですか?

分類Dev

エラーが発生するGoogleスプレッドシートのonOpen()関数を使用しているときに、リアルタイムのスクリプトエラー通知を取得するにはどうすればよいですか?

分類Dev

ファイルtxtのサブディレクトリはすでに存在します。」「txt」という名前のファイルがないのに、ファイルをソートしようとするとエラーが発生する

分類Dev

FtpWebRequestがルートディレクトリからファイルをダウンロードするのはなぜですか?これにより553エラーが発生する可能性がありますか?

分類Dev

FtpWebRequestがルートディレクトリからファイルをダウンロードするのはなぜですか?これにより553エラーが発生する可能性がありますか?

分類Dev

モデルをマップするときにオートマッパーでエラーが発生するのはなぜですか?

分類Dev

selectedItemBuilderとヒントでDropdownButtonを使用しているときに、フラッターでタイプエラーが発生するのはなぜですか?

Related 関連記事

  1. 1

    Dieselのトレイトを使用して関数をトレイトメソッドに書き換えるときに、「要件を評価するオーバーフロー」が発生するのはなぜですか?

  2. 2

    Goのselectステートメントの外に条件を移動すると、このデッドロックが発生するのはなぜですか

  3. 3

    postgresqlテーブルを作成するときに「複数のデフォルト値」エラーが発生するのはなぜですか?

  4. 4

    定義する前にクラスのオブジェクトを宣言すると、フレンドクラスではエラーが発生するが、フレンド関数ではエラーが発生しないのはなぜですか

  5. 5

    子構造のメソッドの結果を返すときに借用エラーが発生するのはなぜですか?

  6. 6

    範囲関数を使用してリストにデータを入力すると、%dで印刷するとリストのフォーマットエラーが発生するのはなぜですか?

  7. 7

    c ++:テンプレート関数のすべての型パラメーターを指定するとエラーが発生するのに、パラメーターを省略すると問題が発生するのはなぜですか?

  8. 8

    デフォルトのメソッドパラメータをC#のコンパイル時定数にする必要があるのはなぜですか

  9. 9

    アプリディレクトリにgulp-sassをインストールするときにエラーが発生するのはなぜですか?

  10. 10

    定数を使用すると未定義のローカル変数またはメソッドエラーが発生するのに、メソッドを使用するとエラーが発生しないのはなぜですか?

  11. 11

    シングルトンクラスのQtメッセージハンドラーメンバー関数を呼び出すとエラーが発生するのはなぜですか:引数リストがありませんか?

  12. 12

    data.table行フィルタリングが、エラーを発生させることなく、関数内の欠落している引数をサイレントに受け入れることができるのはなぜですか?

  13. 13

    dpkginfoディレクトリのext4でファイルを移動または削除するときにエラーが発生しました

  14. 14

    try/except recursive(?) 関数でトレースバック エラーが発生するのはなぜですか?

  15. 15

    Ubuntuサーバーのnodejsでディレクトリを動的に作成しているときにエラーが発生するのはなぜですか?

  16. 16

    プログラムでメソッドスタブを実装するときに、IntelliJがデフォルトで各メソッドをオーバーライドするのはなぜですか?

  17. 17

    ファイルをコミットするときにLibgit2によってエラー「NoMemory」が発生するのはなぜですか?

  18. 18

    ocaml-cohttp Client.postメソッドでHTTPSサーバーをリクエストするときにHANDSHAKE_FAILUREをデバッグする方法は?(そして、なぜこのエラーが発生するのですか?)

  19. 19

    Pythonにフォーマット関数とフォーマットメソッドがあるのはなぜですか

  20. 20

    デフォルトのケースとラムダ関数でswitchステートメントを使用するとgccエラーが発生します

  21. 21

    unordered_mapにemplaceメソッドを使用すると、コンパイルエラーが発生するのはなぜですか?

  22. 22

    デフォルトのパラメータ値を追加すると、引数を変更するときの動作が変わるのはなぜですか?

  23. 23

    コードをコンパイルしようとすると、あいまいなメソッドエラーが発生するのはなぜですか?

  24. 24

    エラーが発生するGoogleスプレッドシートのonOpen()関数を使用しているときに、リアルタイムのスクリプトエラー通知を取得するにはどうすればよいですか?

  25. 25

    ファイルtxtのサブディレクトリはすでに存在します。」「txt」という名前のファイルがないのに、ファイルをソートしようとするとエラーが発生する

  26. 26

    FtpWebRequestがルートディレクトリからファイルをダウンロードするのはなぜですか?これにより553エラーが発生する可能性がありますか?

  27. 27

    FtpWebRequestがルートディレクトリからファイルをダウンロードするのはなぜですか?これにより553エラーが発生する可能性がありますか?

  28. 28

    モデルをマップするときにオートマッパーでエラーが発生するのはなぜですか?

  29. 29

    selectedItemBuilderとヒントでDropdownButtonを使用しているときに、フラッターでタイプエラーが発生するのはなぜですか?

ホットタグ

アーカイブ