如何在迭代器上调用count并仍使用迭代器的项?

时间:2015-01-30 10:17:30

标签: rust

parts.count()会导致所有权转移,因此parts无法继续使用。

fn split(slice: &[u8], splitter: &[u8]) -> Option<Vec<u8>> {
    let mut parts = slice.split(|b| splitter.contains(b));

    let len = parts.count(); //ownership transfer

    if len >= 2 {
        Some(parts.nth(1).unwrap().to_vec())
    } else if len >= 1 {
        Some(parts.nth(0).unwrap().to_vec())
    } else {
        None
    }
}

fn main() {
    split(&[1u8, 2u8, 3u8], &[2u8]);
}

3 个答案:

答案 0 :(得分:4)

如果您只需要使用第一部分或第二部分,也可以避免不必要的Vec分配:

fn split<'a>(slice: &'a [u8], splitter: &[u8]) -> Option<&'a [u8]> {
    let mut parts = slice.split(|b| splitter.contains(b)).fuse();

    let first = parts.next();
    let second = parts.next();

    second.or(first)
}

然后,如果您确实需要Vec,则可以在结果上进行映射:

split(&[1u8, 2u8, 3u8], &[2u8]).map(|s| s.to_vec())

当然,如果您愿意,可以将to_vec()转换为功能:

second.or(first).map(|s| s.to_vec())

我在迭代器上调用fuse(),以保证在返回第一个None后它总是返回None(一般迭代器无法保证)协议)。

答案 1 :(得分:1)

您可以做的一件事是collect新拥有的Vec中拆分的结果,如下所示:

fn split(slice: &[u8], splitter: &[u8]) -> Option<Vec<u8>> {
    let parts: Vec<&[u8]> = slice.split(|b| splitter.contains(b)).collect();

    let len = parts.len();

    if len >= 2 {
        Some(parts.iter().nth(1).unwrap().to_vec())
    } else if len >= 1 {
        Some(parts.iter().nth(0).unwrap().to_vec())
    } else {
        None
    }
}

答案 2 :(得分:1)

其他答案是回答问题的好建议,但我想指出另一个通用解决方案:创建多个迭代器:

fn split(slice: &[u8], splitter: &[u8]) -> Option<Vec<u8>> {
    let mut parts = slice.split(|b| splitter.contains(b));
    let parts2 = slice.split(|b| splitter.contains(b));

    let len = parts2.count();

    if len >= 2 {
        Some(parts.nth(1).unwrap().to_vec())
    } else if len >= 1 {
        Some(parts.nth(0).unwrap().to_vec())
    } else {
        None
    }
}

fn main() {
    split(&[1u8, 2u8, 3u8], &[2u8]);
}

通常可以创建多个只读迭代器。有些迭代器甚至实现Clone,所以你可以说iter.clone().count()。不幸的是,Split不是其中之一,因为它拥有传入的闭包。