.iter().collect() меняет тип?

64 views
Skip to first unread message

Mike Potanin

unread,
Nov 27, 2014, 9:53:22 AM11/27/14
to rust-r...@googlegroups.com

 Добрый вечер!
Я чего-то недопонимаю.
fn main() {
let r:Vec<char> = vec!['1'];
let r1:Vec<char> = r.iter().collect();
println!("{}", r1);
}

При компиляции говорит
<anon>:3:22: 3:40 error: the trait `core::iter::FromIterator<&char>` is not implemented for the type `collections::vec::Vec<char>` <anon>:3 let r1:Vec<char> = r.iter().collect(); ^~~~~~~~~~~~~~~~~~ error: aborting due to previous error playpen: application terminated with error code 101

Я думал, что .collect() обратная операция к .iter(). Разве не так?

Vladimir Matveev

unread,
Nov 27, 2014, 10:13:59 AM11/27/14
to Mike Potanin, rust-r...@googlegroups.com
Добрый вечер!

> Я думал, что .collect() обратная операция к .iter(). Разве не так?

Нет, не так. Эти операции никак не связаны, и `collect()` присутствует на любом итераторе, даже таком, который не был получен из какой-то коллекции. `collect()` «собирает» итератор с помощью трейта `FromIterator` [1] в объект любого типа, который реализует этот трейт. Соответственно, если это коллекция, то её элементами, скорее всего, будут значения, которые возвращает итератор («скорее всего» потому, что реализация `FromIterator` может быть произвольной, в том числе такой, которая разыменовывает ссылки, но для стандартных коллекций поведение «естественное», поэтому никакого разыменования там нет).

[1]: http://doc.rust-lang.org/std/iter/trait.FromIterator.html

Если `r` - это `Vec<T>`, то `r.iter()` вернёт итератор, возвращающий ссылки на элементы вектора, т.е. нечто, реализующее `Iterator<&T>`. В данном случае это будет `&char`. Соответственно, если вы сделаете `collect()` на этом итераторе, то на выходе получите коллекцию, содержащую `&char`:

let r1: Vec<&char> = r.iter().collect();

Точно так же можно собрать, например, `RingBuf`, всё из того же итератора:

let r1: RingBuf<&char> = r.iter().collect();

Тип элемента, кстати, можно опустить, Rust сам его выведет:

let r1: RingBuf<_> = r.iter.collect();

Если вы хотите получить итератор, возвращающий char, то у вас есть несколько выходов.

1. Воспользоваться `map()`:
let r1: Vec<char> = r.iter().map(|&c| c).collect(); // или .map(|c| *c)
Это будет работать только для `Copy`-типов (ну или `Clone`-типов, если `|&c| c|` заменить на `|c| c.clone()`).
2. Воспользоваться `into_iter()` - более общий способ, не требующий копирования элементов, но «поглощающий» сам вектор:
let r1: Vec<char> = r.into_iter().collect();

В некотором роде, `into_iter()` гораздо ближе к «обратной операции к `collect()`», но, как бы то ни было, они не связаны непосредственно.

Mike Potanin

unread,
Nov 27, 2014, 10:44:03 AM11/27/14
to rust-r...@googlegroups.com, mpot...@gmail.com

Спасибо!
Старый вектор мне не жалко, буду использовать .into_iter().
Reply all
Reply to author
Forward
0 new messages