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

前言

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

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

结果遇到大坑git

报错代码

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)  # ============ 这里!
    }
}

编译器报错:app

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.未约束的生命周期

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

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的关系,因此报错。3d

解决办法

1.修改设计

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

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

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

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中如何实现返回可变引用的迭代器?

相关文章
相关标签/搜索