筆者想實現一個RowMutIter, 它產出RatMat某行的元素的可變引用, 設想中能夠這樣使用它:html
for x in ratmat.get_mut_row(1).unwrap(){ *x += 1; // x類型是&mut Node }
結果遇到大坑git
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
生命週期沒法推導。由於輸入參數包含self, 則輸出要和self是一致的。可是Item=&'a Node, 沒辦法推導'a 和 self的關係。
那麼修改成:工具
type Item = &Node;
能夠不? 不能夠,編譯器提示missing lifetime parameter。
因此這裏的設計有問題。學習
修改代碼以下, 這是筆者想表達的: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
根據生命週期省略規則, 若是傳入參數有&self or &mut self, 那麼返回引用的lifetime與self一致。可是 Item = &'a Node, 沒法得知 'a 與 self的關係,因此報錯。3d
費了半天, 終於找到一份對筆者有幫助的資料:
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)
這樣的方式實現。
筆者查看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中如何實現返回可變引用的迭代器?