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

a collection of type `str` cannot be built from `std::iter::Iterator<Item=char>`

以下代码无法编译

1
2
3
4
5
6
fn main() {
    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    s += &v.into_iter().collect();
}

,错误:

1
2
3
4
5
6
7
error[E0277]: a collection of type `str` cannot be built from an iterator over elements of type `char`
 --> src/main.rs:5:25
  |
5 |     s += &v.into_iter().collect();
  |                         ^^^^^^^ a collection of type `str` cannot be built from `std::iter::Iterator<Item=char>`
  |
  = help: the trait `std::iter::FromIterator<char>` is not implemented for `str`

但是此修改似乎有效:

1
2
3
4
5
6
7
fn main() {
    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    let t: String = v.into_iter().collect();
    s += &t;
}

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


首先,什么起作用:

1
2
3
4
5
6
fn main() {
    let n = 10;
    let mut s = String::new();
    let v = vec!['a'; n];
    s += &v.into_iter().collect::<String>();
}

其次,让我们探讨一下为什么行得通。您可以在String上执行add-assign +=,因为它实现了AddAssign特征:

1
impl<'_> AddAssign<&'_ str> for String

,但仅当右侧是&str时。因此,在您的第一个示例中,rustc尝试将char的向量收集到str中。它不起作用,因为Iterator::collect

的签名

1
2
3
fn collect(self) -> B
where
    B: FromIterator<Self::Item>,

指示只能将迭代器收集到实现FromIterator的容器中。在所有实现它的类型中,您可以看到str不是其中之一,但是String是。那是您目睹的错误消息。

另一方面,在第二个示例和此答案中的代码中,明确告诉rustc收集到String中。并且由于Stringstr作为目标类型实现了Deref特征:

1
2
3
impl Deref for String {
    type target = str;
}

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

所以现在您应该能够解释为什么以下有趣的代码也可以工作了:

1
2
3
4
5
6
7
8
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>>();
}