hyperion/20-dev/00-rust/iterators/it.md

98 lines
No EOL
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Ты абсолютно прав! Rust ощущается как "Lego Technic": детали (типы, трейты) либо идеально защелкиваются (type check passed), либо ты физически не можешь их соединить. В C++ часто можно "насильно" прикрутить деталь изолентой (reinterpret_cast), и она отвалится на ходу.
### 1. Как создавать методы для функциональных цепочек?
Да, ты можешь писать методы, которые "чейнятся" (chaining). Секрет в том, что метод должен:
1. Принимать `self` (по значению) — это называется **builder pattern** или **consuming builder**.
2. Возвращать `Self`.
```rust
struct Config {
port: u16,
debug: bool,
}
impl Config {
fn new() -> Self {
Self { port: 80, debug: false }
}
// Принимает 'mut self', меняет его и возвращает 'Self'
fn set_port(mut self, port: u16) -> Self {
self.port = port;
self // Возвращаем измененный объект дальше по конвейеру
}
fn enable_debug(mut self) -> Self {
self.debug = true;
self
}
}
fn main() {
// Функциональная цепочка!
let conf = Config::new()
.set_port(8080)
.enable_debug();
}
```
Если ты про цепочки типа `.map().filter()`, то там возвращается не `Self`, а новый тип-обертка (например, `Map<Iter>`), который реализует тот же трейт `Iterator`.
***
### 2. Как работает магия `collect()`?
`collect()` — это, пожалуй, самый "волшебный" метод в Rust. Он умеет превращать итератор во **что угодно**, что реализует трейт `FromIterator`.
#### Сигнатура collect (упрощенно)
```rust
fn collect<B>(self) -> B
where
B: FromIterator<Self::Item>;
```
Он говорит: "Я могу стать типом `B`, если тип `B` умеет создавать себя из моих элементов".
#### Как это работает внутри?
Когда ты пишешь:
```rust
let vec: Vec<i32> = iter.collect();
```
1. Rust видит, что ты хочешь получить `Vec<i32>`.
2. Он ищет реализацию `impl FromIterator<i32> for Vec<i32>`.
3. В этой реализации (в стандартной библиотеке) написано примерно следующее:
```rust
// Псевдокод реализации внутри std
impl<T> FromIterator<T> for Vec<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut vec = Vec::new();
for item in iter {
vec.push(item);
}
vec
}
}
```
То есть `collect` просто делегирует работу методу `from_iter` целевого типа.
#### Почему это круто?
Ты можешь реализовать `FromIterator` для **своей структуры**, и `collect` начнет работать для неё автоматически!
```rust
struct MyCollection(Vec<i32>);
// Учим нашу коллекцию создаваться из итератора
impl FromIterator<i32> for MyCollection {
fn from_iter<T: IntoIterator<Item = i32>>(iter: T) -> Self {
let mut c = MyCollection(Vec::new());
for i in iter {
c.0.push(i);
}
c
}
}
fn main() {
let my_col: MyCollection = vec![1, 2, 3].into_iter().collect(); // Работает!
}
```