次の例のようないくつかの構造があり、
next()
にあるとしますメソッドユーザー提供のバッファーを使用して次のイベントをプルする必要がありますが、このイベントがコメントであり、コメントフラグを無視するフラグがtrueに設定されている場合、次のイベントをプルする必要があります。
struct Parser {
ignore_comments: bool,
}
enum XmlEvent<'buf> {
Comment(&'buf str),
Other(&'buf str),
}
impl Parser {
fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
let result = loop {
buffer.clear();
let temp_event = self.parse_outside_tag(buffer);
match temp_event {
XmlEvent::Comment(_) if self.ignore_comments => {}
_ => break temp_event,
}
};
result
}
fn parse_outside_tag<'buf>(&mut self, _buffer: &'buf mut String) -> XmlEvent<'buf> {
unimplemented!()
}
}
ただし、このコードでは、
#![feature(nll)]
を持っている場合でも、二重借用エラーが発生します。有効:
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:14:13
|
14 | buffer.clear();
| ^^^^^^ second mutable borrow occurs here
15 |
16 | let temp_event = self.parse_outside_tag(buffer);
| ------ first mutable borrow occurs here
|
note: borrowed value must be valid for the lifetime 'buf as defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:16:53
|
16 | let temp_event = self.parse_outside_tag(buffer);
| ^^^^^^ mutable borrow starts here in previous iteration of loop
|
note: borrowed value must be valid for the lifetime 'buf as defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
NLL機能をオフにすると、ここでエラーが発生する理由は(少なくとも)理解できますが、NLLでエラーが発生する理由はわかりません。
とにかく、私の最終目標はフラグなしでこれを実装することですので、私もこれを試しました(再帰的です、これは本当に残念ですが、私が思いついたすべての非再帰的バージョンはおそらくNLLなしでは動作しませんでした):
fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
buffer.clear();
{
let temp_event = self.parse_outside_tag(buffer);
match temp_event {
XmlEvent::Comment(_) if self.ignore_comments => {}
_ => return temp_event,
}
}
self.next(buffer)
}
ここで、字句ブロック内に借用を制限しようとしました。何もない このブロックから外部に漏れます。ただし、まだエラーが発生します。
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:23:19
|
15 | let temp_event = self.parse_outside_tag(buffer);
| ------ first mutable borrow occurs here
...
23 | self.next(buffer)
| ^^^^^^ second mutable borrow occurs here
24 | }
| - first borrow ends here
error: aborting due to previous error
また、NLLは修正しません。
私が理解できない借用チェックエラーに遭遇してから長い時間が経ちましたので、それが実際には何かの理由で見落としている単純なものであることを望んでいます:)
私は本当に根本原因が何らかの形で明示的な
'buf
に関係していると疑っていますライフタイム(特に、NLLフラグがオンになっているエラーには、これらのメモがあります)が、ここで正確に何が間違っているのか理解できません。
関連した質問
- 複数の可変および不変の借用のベストプラクティスは何ですか?
- 安全でないものを使用せずに割り込みエラーが発生しなくなるまで、bufread - : fill_bufを呼び出す関数を作成することは可能ですか?
- Rust:オプションから値を移動してスタックにプッシュする
- ベクター内のアイテムの情報に基づいてベクターを変更するにはどうすればよいですか?
- 手動で削除された参照ラッパーによる錆びの寿命の問題
- 参照を返す関数を呼び出すときの非語彙の有効期間を理解する
- Rustの反復中にイテレータを再帰呼び出しに渡す
- Rust借用チェッカー:配列インデックスで可変として借用できません
- コードのさまざまな場所で可変でない変数を使用すると、借用エラーが表示されるのはなぜですか?
- Rust:借りた構造体を借りた列挙型に渡しますか?
これは、現在の実装の制限です非字句寿命 これは、この縮小されたケースで表示できます。
この制限により、NLLケース#3が防止されます。機能間の条件付き制御フロー
コンパイラ開発者の用語では、現在の非字句の有効期間の実装は「場所に依存しない」です。ロケーションの感度はもともと利用可能でしたが、パフォーマンスの名前で無効にされました。
Niko Matsakisにこのコードについて質問しました。
幸いなことに、この場所の感度の概念を元に戻すことは、非字句的ライフタイムの実装の強化と見なされます。悪いニュース:
(注:しましたじゃない Rust 2018の最初のリリースに含める)
これは、パフォーマンスを向上させる非字句的ライフタイムの(さらに新しい!)基礎となる実装に依存します。
-Z polonius
を使用して、この半分実装されたバージョンにオプトインできます。 :これは機能全体、関数をインライン化することでこれを回避できる場合があります。