【问题标题】:How to return an iterator for a tuple of slices that iterates the first slice then the second slice?如何返回迭代第一个切片然后迭代第二个切片的切片元组的迭代器?
【发布时间】:2023-01-08 06:21:10
【问题描述】:

我有一个将切片分成三部分的函数,前导切片和尾随切片,以及对中间元素的引用。

/// The leading and trailing parts of a slice.
struct LeadingTrailing<'a, T>(&'a mut [T], &'a mut [T]);

/// Divides one mutable slice into three parts, a leading and trailing slice,
/// and a reference to the middle element.
pub fn split_at_rest_mut<T>(x: &mut [T], index: usize) -> (&mut T, LeadingTrailing<T>) {
    debug_assert!(index < x.len());
    let (leading, trailing) = x.split_at_mut(index);
    let (val, trailing) = trailing.split_first_mut().unwrap();
    (val, LeadingTrailing(leading, trailing))
}

我想为 LeadingTrailing&lt;'a, T&gt; 实现迭代器,以便它首先迭代第一个切片,然后迭代第二个切片。即,它的行为类似于:

let mut foo = [0,1,2,3,4,5];
let (item, lt) = split_at_rest_mut(&foo, 2);
for num in lt.0 {
    ...
}
for num in lt.1 {
    ...
}

我试过转换成Chain

struct LeadingTrailing<'a, T>(&'a mut [T], &'a mut [T]);
impl <'a, T> LeadingTrailing<'a, T> {
    fn to_chain(&mut self) -> std::iter::Chain<&'a mut [T], &'a mut [T]> {
        self.0.iter_mut().chain(self.1.iter_mut())
    }
}

但我得到错误:

89 |         self.0.iter_mut().chain(self.1.iter_mut())
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&mut [T]`, found struct `std::slice::IterMut`

我也试过创建一个自定义的Iterator

/// The leading and trailing parts of a slice.
struct LeadingTrailing<'a, T>(&'a mut [T], &'a mut [T]);

struct LTOthersIterator<'a, T> {
    data: LeadingTrailing<'a, T>,
    index: usize,
}

/// Iterates over the first slice, then the second slice.
impl<'a, T> Iterator for LTOthersIterator<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let leading_len = self.data.0.len();
        let trailing_len = self.data.1.len();
        let total_len = leading_len + trailing_len;
        match self.index {
            0..=leading_len => {
                self.index += 1;
                self.data.0.get(self.index - 1)
            }
            leading_len..=total_len => {
                self.index += 1;
                self.data.1.get(self.index - leading_len - 1)
            }
        }
    }
}

但我得到错误:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
   --> src\main.rs:104:29
    |
104 |                 self.data.0.get(self.index - 1)
                                  ^^^

这样做的正确方法是什么?

【问题讨论】:

标签: rust iterator


【解决方案1】:

您要么让编译器完成工作:

impl <'a, T> LeadingTrailing<'a, T> {
    fn to_chain(&mut self) -> impl Iterator<Item = &mut T> {
        self.0.iter_mut().chain(self.1.iter_mut())
    }
}

或者指定正确的类型,Chain 采用迭代器,而不是它们从中创建的东西。

impl <'a, T> LeadingTrailing<'a, T> {
    fn to_chain(&'a mut self) -> std::iter::Chain<std::slice::IterMut<'a, T>, std::slice::IterMut<'a, T>> {
        self.0.iter_mut().chain(self.1.iter_mut())
    }
}

【讨论】:

  • 不需要明确的生命周期,只需删除所有生命周期并将LeadingTrailing中的那个替换为'_
【解决方案2】:

to_chain() 的返回值不正确。 为简单起见,只需使用impl Iterator

/// The leading and trailing parts of a slice.
#[derive(Debug)]
pub struct LeadingTrailing<'a, T>(&'a mut [T], &'a mut [T]);

/// Divides one mutable slice into three parts, a leading and trailing slice,
/// and a reference to the middle element.
pub fn split_at_rest_mut<T>(x: &mut [T], index: usize) -> (&mut T, LeadingTrailing<T>) {
    debug_assert!(index < x.len());
    let (leading, trailing) = x.split_at_mut(index);
    let (val, trailing) = trailing.split_first_mut().unwrap();
    (val, LeadingTrailing(leading, trailing))
}

impl<T> LeadingTrailing<'_, T> {
    fn to_chain(&mut self) -> impl Iterator<Item = &mut T> {
        self.0.iter_mut().chain(self.1.iter_mut())
    }
}

fn main() {
    let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8];
    let (x, mut leadtrail) = split_at_rest_mut(&mut arr, 5);

    println!("x: {}", x);
    println!("leadtrail: {:?}", leadtrail);

    for el in leadtrail.to_chain() {
        *el *= 2;
    }

    println!("leadtrail: {:?}", leadtrail);
}
x: 5
leadtrail: LeadingTrailing([0, 1, 2, 3, 4], [6, 7, 8])
leadtrail: LeadingTrailing([0, 2, 4, 6, 8], [12, 14, 16])

完全写出的版本是:

impl<T> LeadingTrailing<'_, T> {
    fn to_chain(&mut self) -> std::iter::Chain<std::slice::IterMut<T>, std::slice::IterMut<T>> {
        self.0.iter_mut().chain(self.1.iter_mut())
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-23
    • 2015-06-16
    • 2015-06-08
    • 2010-11-23
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 2017-10-22
    相关资源
    最近更新 更多