Rust --- 实现一个产生可变引用的迭代器

前言

笔者想实现一个RowMutIter, 它产出RatMat某行的元素的可变引用, 设想中可以这样使用它:

for x in ratmat.get_mut_row(1).unwrap(){
    *x += 1;    // x类型是&mut Node
}

结果遇到大坑

报错代码

1.无法推导生命周期

pub struct RowMutIter<'a>{
    pub ref_vec: &'a mut Vec<Node>,
    pub r_index: usize, 
    pub index: Cell<usize>,
}

impl<'a> Iterator for RowMutIter<'a>{
    type Item = &'a mut Node;

    fn next(&mut self) -> Option<Self::Item>{
        *self.index.get_mut() += 1;
        self.ref_vec.get_mut(self.index.get() - 1)  # ============ 这里!
    }
}

编译器报错:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
   --> src\rational_matrix.rs:436:9
    |
436 |         self.ref_vec.get_mut(self.index.get() - 1)
    |         ^^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 434:5...
   --> src\rational_matrix.rs:434:5
    |
434 | /     fn next(&mut self) -> Option<Self::Item>{
435 | |         *self.index.get_mut() += 1;
436 | |         self.ref_vec.get_mut(self.index.get() - 1)
437 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
   --> src\rational_matrix.rs:436:9
    |
436 |         self.ref_vec.get_mut(self.index.get() - 1)
    |         ^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 431:6...
   --> src\rational_matrix.rs:431:6
    |
431 | impl<'a> Iterator for RowMutIter<'a>{
    |      ^^
    = note: ...so that the types are compatible:
            expected std::iter::Iterator
               found std::iter::Iterator

分析1

生命周期无法推导。因为输入参数包含self, 则输出要和self是一致的。但是Item=&'a Node, 没办法推导'a 和 self的关系。
那么修改为:

type Item = &Node;

可以不? 不可以,编译器提示missing lifetime parameter
所以这里的设计有问题。

2.未约束的生命周期

修改代码如下, 这是笔者想表达的:

impl<'a, 'b:'a> Iterator for RowMutIter<'b>{
    type Item = &'a mut Node;

    fn next(&mut self) -> Option<Self::Item>{
        *self.index.get_mut() += 1;
        self.ref_vec.get_mut(self.index.get() - 1)
    }
}

报错:

error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
   --> src\rational_matrix.rs:431:6
    |
431 | impl<'a, 'b:'a> Iterator for RowMutIter<'b>{
    |      ^^ unconstrained lifetime parameter

分析2

根据生命周期省略规则, 如果传入参数有&self or &mut self, 那么返回引用的lifetime与self一致。但是 Item = &'a Node, 无法得知 'a 与 self的关系,所以报错。

解决办法

1.修改设计

费了半天, 终于找到一份对笔者有帮助的资料:
Can I write an Iterator that mutates itself and then yields a reference into itself?
一位答主指出, compiler不知道self和返回值的lifetime的关系, 可以添加:

fn next(&'a mut self) -> Option<&'a [i8]>

但是这违反了Iterator trait的定义。后者要求:

fn next(&mut self) -> Option<Self::Item>
            ↑------ 必须这样写

答主补充:

The Iterator trait is designed for return values that are independent of the iterator object, which is necessary for iterator adaptors like .collect to be correct and safe.

为什么笔者打算实现这个trait? 因为笔者的RatMat是有理数矩阵, 常常需要做一些行运算、列运算,比如行倍乘、行加法等,将来可能支持换行,删行等操作, 如果这些能够配合std一系列Iterator工具, 那就很有用了。可惜此路不通。
但是笔者后来想,这种对行列的操作也可以通过:

fn apply_to_row<F:FnOnce()..)(row_index:usize, f: F) 
    fn apply_to_col<F:FnOnce()..)(col_index:usize, f: F)

这样的方式实现。

2.Unsafe?

笔者查看Vec的IterMut的实现, 其内部使用了大量unsafe。此外还有一篇博文:
Iterators yielding mutable references
提到了不用unsafe无法实现这样的迭代器,笔者打算细细研读。

疑问

笔者还编写了RowIter, 也就是不可变的行迭代器。其代码基本与RowMutIter相同,可是前者顺利通过编译,而后者不行。这又是为什么?与不可变引用本身实现了Copy有关吗?如果是, Copy在这起到什么作用?

最终解决方法

(未完)

参考

一些(可能)有用的参考:
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中如何实现返回可变引用的迭代器?