Iterator::collect 函数是如何工作的?

Lat*_*ter 3 documentation iterator collect rust

我试图collect通过阅读一些文档来了解函数的全部功能。我遇到了一些挑战,特别是在页面上引用的最后一个例子中(也在下面列出,我的评论内嵌)

let results = [Ok(1), Err("nope"), Ok(3), Err("bad")];

let result: Result<Vec<_>, &str> = results.iter().cloned().collect();

// gives us the first error <-- Point 1
assert_eq!(Err("nope"), result);

let results = [Ok(1), Ok(3)];

let result: Result<Vec<_>, &str> = results.iter().cloned().collect();

// gives us the list of answers
assert_eq!(Ok(vec![1, 3]), result);
Run Code Online (Sandbox Code Playgroud)

我用我自己的一些代码跟进了这段代码(如下所示)

let results: [std::result::Result<i32, &str>; 2] = [Err("nope"), Err("bad")];

let result: Vec<Result<i32, &str>> = results.iter().cloned().collect();

// The following prints <-- Point 2
// "nope"
// "bad"
for x in result{
    println!("{:?}", x.unwrap_err());
}
Run Code Online (Sandbox Code Playgroud)

综观实施FromIterator对该性状Result结构,我们看到它提到,“注意到每个元素的Iterator:如果它是一个Err,没有进一步的元素被理解,并且Err,返回不应该Err发生,一个容器的值每个Result都返回。

这种解释与在第 1 点看到的结果一致,但似乎不适用于第 2 点。在第 2 点中,我期望只打印“nope”而不是两个值。

因此,我试图了解这种(选择性)转换在哪里发生并遇到挑战。

如果我们查看方法定义本身,我们会看到以下内容。

#[inline]
fn from_iter<I: IntoIterator<Item=Result<A, E>>>(iter: I) -> Result<V, E> {
    // FIXME(#11084): This could be replaced with Iterator::scan when this
    // performance bug is closed.

    iter::process_results(iter.into_iter(), |i| i.collect())
}
Run Code Online (Sandbox Code Playgroud)

它表明该into_iter()方法正在迭代器上被调用。搜索into_iter给出了两种实现

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, E> IntoIterator for Result<T, E> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    /// Returns a consuming iterator over the possibly contained value.
    ///
    /// The iterator yields one value if the result is [`Result::Ok`], otherwise none.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let x: Result<u32, &str> = Ok(5);
    /// let v: Vec<u32> = x.into_iter().collect();
    /// assert_eq!(v, [5]);
    ///
    /// let x: Result<u32, &str> = Err("nothing!");
    /// let v: Vec<u32> = x.into_iter().collect();
    /// assert_eq!(v, []);
    /// ```
    #[inline]
    fn into_iter(self) -> IntoIter<T> {
        IntoIter { inner: self.ok() }
    }
}

#[stable(since = "1.4.0", feature = "result_iter")]
impl<'a, T, E> IntoIterator for &'a Result<T, E> {
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,在我对语言的有限理解中,似乎没有人能够解释文档所说的内容以及第 2 点中发生的事情。

有人可以解释一下这是如何工作的,或者将我指向实现此类选择逻辑的源代码中的正确位置吗?

我想理解的不是为什么我们在一个向量中得到所有值而在结果中只得到一个值,而是 a. Err从值列表中选择第一个的代码/逻辑在哪里?为什么Err在列表中收集结果时选择了多个值(根据文档,它应该只是第一个Err值)

mca*_*ton 5

在这个例子中

let result: Vec<Result<i32, &str>> = results.iter().cloned().collect();
Run Code Online (Sandbox Code Playgroud)

您不会收集到 a Result,而是收集到 a ,Vec因此所有值都被收集,原封不动。这是从Vec.

这与根本不同

let result: Result<Vec<_>, &str> = results.iter().cloned().collect();
Run Code Online (Sandbox Code Playgroud)

您收集到 a 的位置Result,它根据是否Err找到a来过滤元素。这来自impl<A, E, V> FromIterator<Result<A, E>> for Result<V, E> where V: FromIterator<A>,.