Iteratorから返されたオブジェクトの可変参照
Iterator
隣のアイテムも露出できるものを作りたいです。これらのアイテムも変更したくない限り、問題なく簡単です。しかし、同じ構造の可変バリアントを作成するにはどうすればよいですか?
不変:
struct NearestNeighbours2D<'a, T> {
mid: &'a T,
left: &'a T,
right: &'a T,
top: &'a T,
bot: &'a T,
}
struct EnumerateNearestNeighbours2D<'a, I>
where I: std::ops::Index<usize> {
x: usize,
y: usize,
width: usize,
height: usize,
inner: &'a I
}
impl<'a, I: std::ops::Index<usize>> Iterator for EnumerateNearestNeighbours2D<'a, I>
where <I as std::ops::Index<usize>>::Output: std::marker::Sized {
type Item = NearestNeighbours2D<'a, I::Output>;
fn next(&mut self) -> std::option::Option<<Self as std::iter::Iterator>::Item> {
let (top, left, mid, right, bot) = (
(self.y - 1) * self.width + self.x,
self.y * self.width + self.x - 1,
self.y * self.width + self.x,
self.y * self.width + self.x + 1,
(self.y + 1) * self.width + self.x,
);
Some(
NearestNeighbours2D {
mid: &self.inner[mid],
left: &self.inner[left],
right: &self.inner[right],
top: &self.inner[top],
bot: &self.inner[bot],
}
)
}
}
存続期間が原因で機能しない可変バリアント:
struct NearestNeighbours2DMut<'a, T> {
mid: &'a mut T,
left: &'a mut T,
right: &'a mut T,
top: &'a mut T,
bot: &'a mut T,
}
struct EnumerateNearestNeighbours2DMut<'a, I>
where I: std::ops::IndexMut<usize> {
x: usize,
y: usize,
width: usize,
height: usize,
inner: &'a mut I
}
impl<'a, I: std::ops::IndexMut<usize>> Iterator for EnumerateNearestNeighbours2DMut<'a, I>
where <I as std::ops::Index<usize>>::Output: std::marker::Sized {
type Item = NearestNeighbours2DMut<'a, I::Output>;
fn next(&mut self) -> std::option::Option<<Self as std::iter::Iterator>::Item> {
let (top, left, mid, right, bot) = (
(self.y - 1) * self.width + self.x,
self.y * self.width + self.x - 1,
self.y * self.width + self.x,
self.y * self.width + self.x + 1,
(self.y + 1) * self.width + self.x,
);
Some(
NearestNeighbours2DMut {
mid: &mut self.inner[mid],
left: &mut self.inner[left],
right: &mut self.inner[right],
top: &mut self.inner[top],
bot: &mut self.inner[bot],
}
)
}
}
コンパイラは次のことを指摘しています。
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src\lib.rs:99:27
|
99 | mid: &mut self.inner[mid],
| ^^^^^^^^^^^^^^^
|
回答
残念ながら、EnumerateNearestNeighbors2DMut
正しく作成する方法はありません-それは不健全です。呼び出すnext
たびに、への前回の呼び出しから返された参照と&mut
重複する可能性のある参照を取得&mut
しnext
ます。これは、それが機能した場合、エイリアスを作成することによって参照のルールに違反することを意味し&mut
ます。
これは、が存在するのと同じ理由ですがstd::slice::Windows、存在しませんWindowsMut
(ただしChunksMut
、チャンクは重複していないため問題ありません)。
いくつかの問題(ここに1つの例)は似たようなエラーメッセージを表示しますが、unsafe
参照されている項目が実際には重複していないため、実際には解決可能です(場合によってはで)。これらのソリューションはここでは機能しません。あなたがすることができれば、それ自体に戻り参照することをイテレータを書く(「ストリーミングイテレータ」)、APIは音作ることができます。ただし、Iterator
これは許可されていません。
ここにあなたのための3つの可能なオプションがあります。確かに他にもあります。
(ネイバーを使用した)可変反復をまったく許可しないでください。共有(
&
)参照を介して反復を公開するだけです。元のグリッドを変更する必要がある場合は、代わりに変更されたコピーを作成し、反復が完了したら元のグリッドと交換します。これは、各出力が複数の入力に依存する画像フィルターやセルオートマトンのようなものを書いている場合、とにかくあなたが望むものであることがよくあります。クロージャを受け入れ、外部反復の代わりにAPIで内部反復を使用します。したがって、このようなものの代わりに:
for neighbors in array.enumerate_2d_neighbors_mut() { println!("{}", neighbors.top); }
あなたはこのようなものを書くでしょう:
array.foreach_2d_neighbors_mut(|neighbors| { println!("{}", neighbors.top); });
この場合、
array
のアイテムへの参照for
はforeach_2d_neighbors_mut
メソッド内のループで取得され、エスケープされません。このAPIは、unsafe
コードがなくても非常に簡単に記述できます。内部可変性を使用する(
Cell
、RefCell
、Atomic???
、など)を介して変異させる&
必要の代わりに参照&mut
。何をしているのかによっては、これが正しい方法かもしれません。がスライスまたはベクトルの場合、タイプを変更せずに内部の可変性にこっそり使用CellIIできることに注意してください。しかし、これはほとんどの場合、私の最初の選択ではありません。