不能从 `std::iter::Iterator<Item=char>` 构建 `str` 类型的集合

RSS*_*RSS 5 rust

以下代码无法编译

fn main() {
    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    s += &v.into_iter().collect();
}
Run Code Online (Sandbox Code Playgroud)

有错误:

fn main() {
    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    s += &v.into_iter().collect();
}
Run Code Online (Sandbox Code Playgroud)

然而,这种修改似乎有效:

fn main() {
    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    let t: String = v.into_iter().collect();
    s += &t;
}
Run Code Online (Sandbox Code Playgroud)

我试图了解原因。任何提示/解释都会有所帮助。谢谢。

edw*_*rdw 6

首先,什么有效:

fn main() {
    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    s += &v.into_iter().collect::<String>();
}
Run Code Online (Sandbox Code Playgroud)

其次,让我们探讨一下为什么会这样。您可以执行 add-assign +=String因为它实现了AddAssigntrait

impl<'_> AddAssign<&'_ str> for String
Run Code Online (Sandbox Code Playgroud)

但前提是右侧是&str. 因此,在您的第一个示例中,rustc尝试收集charinto的向量str。它不会工作,因为签名Iterator::collect

fn collect<B>(self) -> B
where
    B: FromIterator<Self::Item>,
Run Code Online (Sandbox Code Playgroud)

规定迭代器只能收集到实现FromIterator. 在实现它的所有类型中,您可以看到str不是其中之一,而是String。这就是您所看到的错误消息。

另一方面,在您的第二个示例和此答案中的代码中,rustc专门告诉您收集到String. 并且因为String实现了Dereftrait withstr作为目标类型:

impl Deref for String {
    type target = str;
}
Run Code Online (Sandbox Code Playgroud)

a&String可以被强制为&str。编译器现在很高兴。


所以现在您应该能够理解为什么以下看起来很有趣的代码也有效:

fn main() {
    use std::borrow::Cow;

    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    s += &v.into_iter().collect::<Cow<'_, str>>();
}
Run Code Online (Sandbox Code Playgroud)