问题
笔者想实现一个RowMutIter, 它产出RatMat某行的元素的可变引用,同时又可以搭配Iterator
的轮子。设想中可以这样使用它:
// 产生第一行的元素的可变引用
for x in ratmat.get_mut_row(1).unwrap(){
*x += 1; // x类型是&mut Node
}
在为RowMutIter
实现Iterator
时遇到一些问题。
生命周期错误
代码如下:
pub struct RowMutIter<'a, T>{
pub ref_vec: &'a mut Vec<T>,
pub r_index: usize,
pub index: usize,
}
impl<'a, T> Iterator for RowMutIter<'a, T>{
// type Item = &mut T -> 缺少生命周期
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item>{
self.index += 1;
self.ref_vec.get_mut(self.index - 1)
}
}
报错提示E0495
, rustc --explain E0495
看一下,发现是无法推断生命周期关系。根据生命周期的规则,上述代码中有两个生命周期:显式定义的'a
与&mut self
的匿名生命周期'b
。
type Item = &'a mut T
要求返回值是'a
。而根据省略规则,返回值的生命周期与&mut self
一致。
因此产生冲突,无法确定'a
与'b
的关系。接下来尝试修改, 有两种方法:
- 统一返回值生命周期
- 显式标记
'b, 'a
的关系。
修改为:
impl<'a, T> Iterator for RowMutIter<'a, T>{
type Item = &'a mut T;
// 统一返回值的生命周期
fn next(&'a mut self) -> Option<Self::Item>{
self.index += 1;
self.ref_vec.get_mut(self.index - 1)
}
}
报错:
error[E0308]: method not compatible with trait
--> src\main.rs:16:5
|
16 | fn next(&'a mut self) -> Option<Self::Item>{
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&mut RowMutIter<'a, T>) -> std::option::Option<_>`
found fn pointer `fn(&'a mut RowMutIter<'a, T>) -> std::option::Option<_>`
与trait Iterator
的接口约定不一致。
疑问
为什么实现受到限制?
首先,现有的Iterator
的设计中,产出的值和迭代器本身生命周期是独立的。比如RowIterMut<'a>
, 它内部的ref_vec
的生命周期是'a
。而每次调用next(&mut self)
产出的值,其生命周期与&mut self
同为'n
。
在目前的Iterator
定义下, safe rust没法表达'n
与'a
的关系。
std中如何实现产出可变引用的迭代器?
比如Vec
,那么它的iter_mut()
是怎么实现的?
IterMut
内部并没有保存对象的可变引用,而是使用了两个指针ptr, end
, 通过指针运算和cast来产出&mut T
.
如何解决?
一种方法是放弃实现Iterator
, 不使用相关轮子, 如下面代码:
pub struct RowMutIter<'a, T>{
pub ref_vec: &'a mut Vec<T>,
pub r_index: usize,
pub index: usize,
}
trait MutIterator<'a>{
type Item;
fn next(&'a mut self) -> Option<Self::Item>;
}
impl<'a, T> MutIterator<'a> for RowMutIter<'a, T>{
// type Item = &mut T -> 缺少生命周期
type Item = &'a mut T;
fn next(&'a mut self) -> Option<Self::Item>{
self.index += 1;
self.ref_vec.get_mut(self.index - 1)
}
}
还可以使用unsafe代码实现,参考Vec
.
参考
一些(可能)有用的参考:
1.Rust返回引用的不同方式 (译文)
2.Strategies for Returning References in Rust (原文)
3.Rust学习笔记3 所有权和借用
4.RustPrimer 引用借用
5.如何实现一个可变迭代器
6.Vec< Vec<(k, v)>>的可变迭代器,用Flat_map()把二维的for{for{..}}结构展开为一维结构。
7.知乎-rust中如何实现返回可变引用的迭代器?
8.Can I write an Iterator that mutates itself and then yields a reference into itself?
9.Iterators yielding mutable references
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。