today's savings
This commit is contained in:
parent
17f37947f3
commit
171c8d5489
5 changed files with 237 additions and 0 deletions
56
20-dev/00-rust/functional examples/Untitled.md
Normal file
56
20-dev/00-rust/functional examples/Untitled.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
```rust
|
||||
#[derive(Debug)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: u8,
|
||||
}
|
||||
|
||||
impl Default for Person {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: String::from("John"),
|
||||
age: 30,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
impl From<&str> for Person {
|
||||
fn from(s: &str) -> Self {
|
||||
s.split_once(',')
|
||||
.filter(|(name, _)| !name.is_empty())
|
||||
.and_then(|(name, age_str)| {
|
||||
age_str.parse::<u8>().ok().map(|age| (name, age))
|
||||
})
|
||||
.map(|(name, age)| Person {
|
||||
name: name.to_string(),
|
||||
age,
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
как это написать через match:
|
||||
|
||||
```rust
|
||||
impl From<&str> for Person {
|
||||
fn from(s: &str) -> Self {
|
||||
let Some((name, age_str)) = s.split_once(',') else {
|
||||
return Person::default();
|
||||
};
|
||||
if name.is_empty() {
|
||||
return Person::default();
|
||||
}
|
||||
let Ok(age) = age_str.parse::<u8>() else {
|
||||
return Person::default();
|
||||
};
|
||||
Person {
|
||||
name: name.to_string(),
|
||||
age,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
98
20-dev/00-rust/iterators/it.md
Normal file
98
20-dev/00-rust/iterators/it.md
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
Ты абсолютно прав! 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(); // Работает!
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue