问题

笔者想实现一个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的关系。接下来尝试修改, 有两种方法:

  1. 统一返回值生命周期
  2. 显式标记'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()是怎么实现的?
image.png

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


Tsukami
9 声望9 粉丝

语雀: [链接]


下一篇 »
MIT6.824-Lab1-P4