iterator - 如何在 flat_map 中取得一个值的所有权

标签 iterator rust

我的问题的以下简化/抽象版本:

fn main() {
    let foo_selectors = vec![0, 1];

    let foos: Vec<_> = foo_selectors
        .into_iter()
        .flat_map(|i| get_foo(i).into_iter())
        .collect();

    println!("{:?}", foos);
}

fn get_foo(i: u8) -> [u8; 3] {
    if i % 2 == 0 {
        [1, 2, 3]
    } else {
        [4, 5, 6]
    }
}

Playground Link

我收到以下错误消息:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:6:44
   |
6  |         .flat_map(|i| get_foo(i).into_iter())
   |                       ----------           ^ temporary value dropped here while still borrowed
   |                       |
   |                       temporary value created here
...
10 | }
   | - temporary value needs to live until here

错误消息提示借用,但我到处都使用了 into_iter,据我所知,它拥有迭代值的所有权。我想获取从 get_foo 返回的值的所有权,并将它们的元素插入到 foos 中。我该怎么做?

最佳答案

How to take ownership of a value in flat_map

这里的flat_map没有什么特别之处。当调用 get_foo 时,返回值的所有权转移给调用者,就像 Rust 中的其他任何地方一样。

I've used into_iter everywhere, which as I understand it, takes ownership of the iterated values.

通常,是的,但不是数组。请参阅下面的链接问题了解原因。这就是问题的根源。 flat_map 闭包拥有 get_foo 的结果,然后您引用它。引用不能在闭包之后继续存在,但这正是您要求它做的。

作为解决方法,您可以从您的函数返回一个 Vec:

fn get_foo(i: u8) -> Vec<u8> {
    if i % 2 == 0 {
        vec![1, 2, 3]
    } else {
        vec![4, 5, 6]
    }
}

您还可以在 flat_map 调用中将返回的数组转换为 Vec

如果您觉得情况需要,您可以实现自己的迭代器:

struct CloneArrayIter<T> {
    arr: [T; 3],
    idx: usize,
}

impl<T> CloneArrayIter<T> {
    fn new(arr: [T; 3]) -> Self {
        Self { arr, idx: 0 }
    }
}

impl<T> Iterator for CloneArrayIter<T>
where
    T: Clone,
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx < 3 {
            let value = self.arr[self.idx].clone();
            self.idx += 1;
            Some(value)
        } else {
            None
        }
    }
}

并将其用作 .flat_map(|i| CloneArrayIter::new(get_foo(i)))

我可能只使用来自 arrayvecArrayVec虽然:

extern crate arrayvec;

use arrayvec::ArrayVec;

fn main() {
    let foo_selectors = vec![0, 1];

    let foos: Vec<_> = foo_selectors
        .into_iter()
        .flat_map(|i| get_foo(i))
        .collect();

    println!("{:?}", foos);
}

fn get_foo(i: u8) -> ArrayVec<[u8; 3]> {
    if i % 2 == 0 { [1, 2, 3] } else { [4, 5, 6] }.into()
}

另见:

关于iterator - 如何在 flat_map 中取得一个值的所有权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45904760/

相关文章:

c++ - 列表中 -> 运算符的语义(以及一般的 C++)

python迭代字典列表

rust - 关于 Rust Setter

rust - 我可以将 Rust 文档测试的一部分外部化到外部文件吗?

python - 如何为一长串整数创建优化的迭代器?

java - Java HashSet 奇怪的迭代器行为

java - 迭代器是如何创建的?

random - 从时间戳生成确定性随机数

c - 声明静态变量包含指向另一个静态变量的地址

rust - 如何获得特征对象的地址?