Често срещани типажи, итератори и анонимни функции

10 ноември 2022

Често използвани типажи

Често използвани типажи

Стандартната библиотека дефинира често използвани типажи

Често използвани типажи

Стандартната библиотека дефинира често използвани типажи
Голяма част от Rust екосистемата разчита на тях

Често използвани типажи

Стандартната библиотека дефинира често използвани типажи
Голяма част от Rust екосистемата разчита на тях
Само ние можем да имплементираме стандартните trait-ове за наши типове

Често използвани типажи

Стандартната библиотека дефинира често използвани типажи
Голяма част от Rust екосистемата разчита на тях
Само ние можем да имплементираме стандартните trait-ове за наши типове
Затова, ако пишем библиотека, е добре да имплементираме всички стандартни trait-ове, които можем

Често използвани типажи

Списък

Clone

1 2 3 4 5
trait Clone {
    fn clone(&self) -> Self;

    fn clone_from(&mut self, source: &Self) { ... }
}

Clone

1 2 3 4 5
trait Clone {
    fn clone(&self) -> Self;

    fn clone_from(&mut self, source: &Self) { ... }
}

Clone

1 2 3 4 5
trait Clone {
    fn clone(&self) -> Self;

    fn clone_from(&mut self, source: &Self) { ... }
}

Clone

1 2 3 4 5
trait Clone {
    fn clone(&self) -> Self;

    fn clone_from(&mut self, source: &Self) { ... }
}

Clone

1 2 3 4 5
trait Clone {
    fn clone(&self) -> Self;

    fn clone_from(&mut self, source: &Self) { ... }
}

Clone

1 2 3 4 5
trait Clone {
    fn clone(&self) -> Self;

    fn clone_from(&mut self, source: &Self) { ... }
}

Copy

1
trait Copy: Clone { }

Copy

1
trait Copy: Clone { }

Copy

1
trait Copy: Clone { }

Copy

1
trait Copy: Clone { }

Copy

1
trait Copy: Clone { }

Copy

1
trait Copy: Clone { }

Copy

1
trait Copy: Clone { }

Copy

1
trait Copy: Clone { }

Можем да имплементираме Copy само ако:

Copy

1
trait Copy: Clone { }

Можем да имплементираме Copy само ако:

Copy

1
trait Copy: Clone { }

Можем да имплементираме Copy само ако:

Drop

1 2 3
pub trait Drop {
    fn drop(&mut self);
}

Drop

1 2 3
pub trait Drop {
    fn drop(&mut self);
}

Drop

1 2 3
pub trait Drop {
    fn drop(&mut self);
}

Drop

1 2 3
pub trait Drop {
    fn drop(&mut self);
}

Drop

1 2 3
pub trait Drop {
    fn drop(&mut self);
}

Drop

1 2 3
pub trait Drop {
    fn drop(&mut self);
}

Default

1 2 3
trait Default {
    fn default() -> Self;
}

Default

1 2 3
trait Default {
    fn default() -> Self;
}

Default

1 2 3
trait Default {
    fn default() -> Self;
}

Default

1 2 3
trait Default {
    fn default() -> Self;
}

Default

1 2 3
trait Default {
    fn default() -> Self;
}

Hash

Hash

Hash

Hash

Hash

Display & Debug

Вече сме виждали #[derive(Debug)], сега ще разгледаме как да си имлементираме собствени Display и Debug
Те ни позволяват format!, println! и подобни макроси да работят за наш тип

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
struct MagicTrick {
    description: String,
    secrets: Vec<String>,
    skills: Vec<String>,
}

let trick = MagicTrick {
    description: String::from("Изчезваща монета"),
    secrets: vec![String::from("Монетата се прибира в ръкава")],
    skills: vec![String::from("Бързи ръце"), String::from("Заблуда")],
};

println!("{}", trick);
println!("===");
println!("{:?}", trick);
Магически трик "Изчезваща монета" === MagicTrick { description: "Изчезваща монета", secrets: ["Монетата се прибира в ръкава"], skills: ["Бързи ръце", "Заблуда"] }
use std::fmt::{self, Display, Formatter};
impl Display for MagicTrick {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Магически трик {:?}", self.description)
}
}
#[derive(Debug)]
struct MagicTrick {
    description: String,
    secrets: Vec,
    skills: Vec,
}

fn main() {
let trick = MagicTrick {
    description: String::from("Изчезваща монета"),
    secrets: vec![String::from("Монетата се прибира в ръкава")],
    skills: vec![String::from("Бързи ръце"), String::from("Заблуда")],
};

println!("{}", trick);
println!("===");
println!("{:?}", trick);
}

Display

Display

Display

Display

1 2 3 4 5 6 7
use std::fmt::{self, Display, Formatter};

impl Display for MagicTrick {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Магически трик {:?}", self.description)
    }
}
#![allow(dead_code)]
struct MagicTrick { description: String }
fn main() {}
use std::fmt::{self, Display, Formatter};

impl Display for MagicTrick {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Магически трик {:?}", self.description)
    }
}

Display

Нека да разбием примера и да видим какво oзначават новите неща

Макрос write

1
write!(f, "Магически трик {:?}", self.description)

Макрос write

1
write!(f, "Магически трик {:?}", self.description)

Макрос write

1
write!(f, "Магически трик {:?}", self.description)

Formatter структура

Formatter структура

Formatter структура

Display

1 2 3 4 5 6 7 8 9 10 11 12 13
struct MagicTrick {
    description: String,
    secrets: Vec<String>,
    skills: Vec<String>,
}

let trick = MagicTrick {
    description: String::from("Изчезваща монета"),
    secrets: vec![String::from("Монетата се прибира в ръкава")],
    skills: vec![String::from("Бързи ръце"), String::from("Заблуда")],
};

println!("{}", trick);
Магически трик "Изчезваща монета"
#![allow(dead_code)]
use std::fmt::{self, Display, Formatter};
impl Display for MagicTrick {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Магически трик {:?}", self.description)
}
}
struct MagicTrick {
    description: String,
    secrets: Vec,
    skills: Vec,
}

fn main() {
let trick = MagicTrick {
    description: String::from("Изчезваща монета"),
    secrets: vec![String::from("Монетата се прибира в ръкава")],
    skills: vec![String::from("Бързи ръце"), String::from("Заблуда")],
};

println!("{}", trick);
}

Debug

Debug

Debug

Debug

Може да напишем и собствена имплементация

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
use std::fmt::{self, Debug, Formatter};

impl Debug for MagicTrick {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write! {
            f,
r#"Трик
Описание: {:?}
Тайни: {:?}
Умения: {:?}"#,
            self.description,
            self.secrets,
            self.skills
        }
    }
}
#![allow(dead_code)]
fn main() {}
struct MagicTrick {
description: String,
secrets: Vec,
skills: Vec
}
use std::fmt::{self, Debug, Formatter};

impl Debug for MagicTrick {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write! {
            f,
r#"Трик
Описание: {:?}
Тайни: {:?}
Умения: {:?}"#,
            self.description,
            self.secrets,
            self.skills
        }
    }
}

Display & Debug

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
struct MagicTrick {
    description: String,
    secrets: Vec<String>,
    skills: Vec<String>,
}

let trick = MagicTrick {
    description: String::from("Изчезваща монета"),
    secrets: vec![String::from("Монетата се прибира в ръкава")],
    skills: vec![String::from("Бързи ръце"), String::from("Заблуда")],
};

println!("{}", trick);
println!("===");
println!("{:?}", trick);
Магически трик "Изчезваща монета" === Трик Описание: "Изчезваща монета" Тайни: ["Монетата се прибира в ръкава"] Умения: ["Бързи ръце", "Заблуда"]
#![allow(dead_code)]
use std::fmt::{self, Display, Debug, Formatter};
impl Display for MagicTrick {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Магически трик {:?}", self.description)
}
}
impl Debug for MagicTrick {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write! { f,
r#"Трик
Описание: {:?}
Тайни: {:?}
Умения: {:?}"#,
self.description, self.secrets, self.skills
}
}
}
struct MagicTrick {
    description: String,
    secrets: Vec,
    skills: Vec,
}

fn main() {
let trick = MagicTrick {
    description: String::from("Изчезваща монета"),
    secrets: vec![String::from("Монетата се прибира в ръкава")],
    skills: vec![String::from("Бързи ръце"), String::from("Заблуда")],
};

println!("{}", trick);
println!("===");
println!("{:?}", trick);
}

Предефиниране на оператори

Операторите се дефинират с trait-ове

Видяхме trait-а Add, с който дефинираме оператора +

1 2 3 4 5
trait Add<RHS = Self> {
    type Output;

    fn add(self, rhs: RHS) -> Self::Output;
}

Предефиниране на оператори

Примери

Предефиниране на оператори

PartialEq

1 2 3 4 5
trait PartialEq<Rhs = Self> where Rhs: ?Sized {
    fn eq(&self, other: &Rhs) -> bool;

    fn ne(&self, other: &Rhs) -> bool { ... }
}

Предефиниране на оператори

PartialEq

1 2 3 4 5
trait PartialEq<Rhs = Self> where Rhs: ?Sized {
    fn eq(&self, other: &Rhs) -> bool;

    fn ne(&self, other: &Rhs) -> bool { ... }
}

Предефиниране на оператори

PartialEq

1 2 3 4 5
trait PartialEq<Rhs = Self> where Rhs: ?Sized {
    fn eq(&self, other: &Rhs) -> bool;

    fn ne(&self, other: &Rhs) -> bool { ... }
}

Предефиниране на оператори

PartialEq

1 2 3 4 5
trait PartialEq<Rhs = Self> where Rhs: ?Sized {
    fn eq(&self, other: &Rhs) -> bool;

    fn ne(&self, other: &Rhs) -> bool { ... }
}

Предефиниране на оператори

Eq

1
trait Eq: PartialEq<Self> { }

Предефиниране на оператори

Eq

1
trait Eq: PartialEq<Self> { }

Предефиниране на оператори

Eq

1
trait Eq: PartialEq<Self> { }

Предефиниране на оператори

PartialOrd

1 2 3 4 5 6 7 8 9 10 11 12 13 14
trait PartialOrd<Rhs = Self>: PartialEq<Rhs> where Rhs: ?Sized {
    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;

    fn lt(&self, other: &Rhs) -> bool { ... }
    fn le(&self, other: &Rhs) -> bool { ... }
    fn gt(&self, other: &Rhs) -> bool { ... }
    fn ge(&self, other: &Rhs) -> bool { ... }
}

enum Ordering {
    Less,
    Equal,
    Greater,
}

Предефиниране на оператори

PartialOrd

Дефинира операторите < <= > >=

PartialOrd дефинира частична наредба

1 2
assert_eq!(::std::f64::NAN < 0.0, false);
assert_eq!(::std::f64::NAN >= 0.0, false);
fn main() {
assert_eq!(::std::f64::NAN < 0.0, false);
assert_eq!(::std::f64::NAN >= 0.0, false);
}

Предефиниране на оператори

Ord

1 2 3 4 5 6
trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;

    fn max(self, other: Self) -> Self { ... }
    fn min(self, other: Self) -> Self { ... }
}

Дефинира тотална наредба т.е само едно от a < b, a == b, a > b е изпълнено.

Итератори

Итератори

Итераторите имплементират trait, който изглежда така:

1 2 3 4 5 6 7
trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;

    // ... predefined iterator methods ...
}
#![allow(dead_code)]
fn main() {}
trait Iterator {
    type Item;

    fn next(&mut self) -> Option;

    // ... predefined iterator methods ...
}

Итератори

Ето и как може да си имплементиране собствен итератор

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
struct OneTwoThree {
    state: u32,
}

impl OneTwoThree {
    fn new() -> Self {
        Self { state: 0 }
    }
}

impl Iterator for OneTwoThree {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.state < 3 {
            self.state += 1;
            Some(self.state)
        } else {
            None
        }
    }
}
#![allow(dead_code)]
fn main() {}
struct OneTwoThree {
    state: u32,
}

impl OneTwoThree {
    fn new() -> Self {
        Self { state: 0 }
    }
}

impl Iterator for OneTwoThree {
    type Item = u32;

    fn next(&mut self) -> Option {
        if self.state < 3 {
            self.state += 1;
            Some(self.state)
        } else {
            None
        }
    }
}

Итератори

1 2 3 4 5 6 7 8 9 10
fn main() {
    let mut iter = OneTwoThree::new();

    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    // ...
}
Some(1) Some(2) Some(3) None None
#![allow(dead_code)]
struct OneTwoThree {
state: u32,
}
impl Iterator for OneTwoThree {
type Item = u32;
fn next(&mut self) -> Option {
if self.state < 3 { self.state += 1 ; Some(self.state) } else { None }
}
}
impl OneTwoThree {
fn new() -> Self {
Self { state: 0 }
}
}
fn main() {
    let mut iter = OneTwoThree::new();

    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    // ...
}

Итератори

IntoIterator

Указва как може един тип да се конвертира до итератор.

1 2 3 4 5 6
trait IntoIterator
{
    type Item;
    type IntoIter: Iterator<Item=Self::Item>;
    fn into_iter(self) -> Self::IntoIter;
}

Итератори

IntoIterator

1 2 3 4 5 6
let v = vec![1, 2, 3];
let mut iter = v.into_iter();

while let Some(i) = iter.next() {
    println!("{}", i);
}
1 2 3
#![allow(dead_code)]
fn main() {
let v = vec![1, 2, 3];
let mut iter = v.into_iter();

while let Some(i) = iter.next() {
    println!("{}", i);
}
}

Итератори

IntoIterator

Също така получаваме и благото да използваме типа директно във for-in цикли

Тъй като векторите имплементират този типаж, следните два примера са еднакви

1 2 3 4 5
let v = vec![1, 2, 3];

for i in v.into_iter() {
    println!("{}", i);
}

1 2 3

#![allow(dead_code)]
fn main() {
let v = vec![1, 2, 3];

for i in v.into_iter() {
    println!("{}", i);
}
}

1 2 3 4 5
let v = vec![1, 2, 3];

for i in v {
    println!("{}", i);
}

1 2 3

#![allow(dead_code)]
fn main() {
let v = vec![1, 2, 3];

for i in v {
    println!("{}", i);
}
}

Итератори

for-in цикъл

Нека отбележим и доста важен факт, че всеки итератор има имплементиран IntoIterator

1 2 3 4 5 6 7 8
impl<I: Iterator> IntoIterator for I {
    type Item = I::Item;
    type IntoIter = I;

    fn into_iter(self) -> I {
        self
    }
}

Итератори

for-in цикъл

1 2 3 4 5
let values = vec![1, 2, 3];

for x in values {
    println!("{}", x);
}
1 2 3
#![allow(dead_code)]
fn main() {
let values = vec![1, 2, 3];

for x in values {
    println!("{}", x);
}
}

Rust генерира следният код зад всеки for-in цикъл:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let values = vec![1, 2, 3];
{
    let result = match IntoIterator::into_iter(values) {
        mut iter => loop {
            let next;
            match iter.next() {
                Some(val) => next = val,
                None => break,
            };
            let x = next;
            let () = { println!("{}", x); };
        },
    };
    result
}
1 2 3
#![allow(dead_code)]
fn main() {
let values = vec![1, 2, 3];
{
    let result = match IntoIterator::into_iter(values) {
        mut iter => loop {
            let next;
            match iter.next() {
                Some(val) => next = val,
                None => break,
            };
            let x = next;
            let () = { println!("{}", x); };
        },
    };
    result
}
}

Итератори

FromIterator

Обратно на IntoIterator, FromIterator се използва за да укаже как един итератор да се конвертира до тип, най-често структура от данни.

1 2 3
trait FromIterator<A>: Sized {
    fn from_iter<T: IntoIterator<Item=A>>(iter: T) -> Self;
}

Итератори

FromIterator

Обратно на IntoIterator, FromIterator се използва за да укаже как един итератор да се конвертира до тип, най-често структура от данни.

1 2 3
trait FromIterator<A>: Sized {
    fn from_iter<T: IntoIterator<Item=A>>(iter: T) -> Self;
}

Ще видим как това е полезно при итератор адаптeрите.

Итератори

Vec

Има две интересни имплементации на Iterator за Vec, освен стандартната

1 2 3 4
impl<T> IntoIterator for Vec<T>

impl<'a, T> IntoIterator for &'a mut Vec<T>
impl<'a, T> IntoIterator for &'a Vec<T>

Итератори

Vec

които позволяват взаимно заменяемия код

1 2 3 4
let v = vec![1, 2, 3];
for i in v.iter() {
    println!("{}", i);
}

1 2 3

fn main() {
let v = vec![1, 2, 3];
for i in v.iter() {
    println!("{}", i);
}
}

1 2 3 4
let v = vec![1, 2, 3];
for i in &v {
    println!("{}", i);
}

1 2 3

fn main() {
let v = vec![1, 2, 3];
for i in &v {
    println!("{}", i);
}
}

Итератори

Vec

както и mutable версията

1 2 3 4 5
let mut v = vec![1, 2, 3];
for i in v.iter_mut() {
    *i += 1;
}
println!("{:?}", v);

[2, 3, 4]

fn main() {
let mut v = vec![1, 2, 3];
for i in v.iter_mut() {
    *i += 1;
}
println!("{:?}", v);
}

1 2 3 4 5
let mut v = vec![1, 2, 3];
for i in &mut v {
    *i += 1;
}
println!("{:?}", v);

[2, 3, 4]

fn main() {
let mut v = vec![1, 2, 3];
for i in &mut v {
    *i += 1;
}
println!("{:?}", v);
}

Итератори

Адаптери

Итератори

Адаптери

1 2 3 4 5
let v = vec![1, 2, 3];
let iter = v.into_iter().map(|x| x + 1).filter(|&x| x < 4);
for i in iter {
    println!("{}", i);
}
2 3
fn main() {
let v = vec![1, 2, 3];
let iter = v.into_iter().map(|x| x + 1).filter(|&x| x < 4);
for i in iter {
    println!("{}", i);
}
}

Итератори

Адаптери

1 2 3 4 5
let v = vec![1, 2, 3];
let iter = v.into_iter().map(|x| x + 1).filter(|&x| x < 4);
for i in iter {
    println!("{}", i);
}
2 3
fn main() {
let v = vec![1, 2, 3];
let iter = v.into_iter().map(|x| x + 1).filter(|&x| x < 4);
for i in iter {
    println!("{}", i);
}
}

Итератори

Адаптери

1 2 3 4 5
let v = vec![1, 2, 3];
let iter = v.into_iter().map(|x| x + 1).filter(|&x| x < 4);
for i in iter {
    println!("{}", i);
}
2 3
fn main() {
let v = vec![1, 2, 3];
let iter = v.into_iter().map(|x| x + 1).filter(|&x| x < 4);
for i in iter {
    println!("{}", i);
}
}

Итератори

Адаптери

1 2 3 4 5 6 7 8
let v = vec![1, 2, 3];
let v = v
    .into_iter()
    .map(|x| x + 1)
    .filter(|&x| x < 4)
    .collect::<Vec<_>>();

println!("{:?}", v);
[2, 3]
fn main() {
let v = vec![1, 2, 3];
let v = v
    .into_iter()
    .map(|x| x + 1)
    .filter(|&x| x < 4)
    .collect::>();

println!("{:?}", v);
}

Итератори

Адаптери

1 2 3 4 5 6 7 8
let v = vec![1, 2, 3];
let v = v
    .into_iter()
    .map(|x| x + 1)
    .filter(|&x| x < 4)
    .collect::<Vec<_>>();

println!("{:?}", v);
[2, 3]
fn main() {
let v = vec![1, 2, 3];
let v = v
    .into_iter()
    .map(|x| x + 1)
    .filter(|&x| x < 4)
    .collect::>();

println!("{:?}", v);
}

Това е възможно, защото collect извиква FromIterator::from_iter.

Итератори

Има някои интересни имплементации на FromIterator.
Например връщане на единичен резултат от итеаратор с резултати:

1 2 3 4 5 6 7 8 9 10 11 12 13
fn batch(v: Vec<Result<u32, u32>>) -> Result<Vec<u32>, u32> {
    v.into_iter().collect()
}

fn only_err(v: Vec<Result<(), u32>>) -> Result<(), u32> {
    v.into_iter().collect()
}

println!("{:?}", batch(vec![Ok(1), Ok(2), Ok(3)]));
println!("{:?}", batch(vec![Ok(1), Err(2), Err(3)]));
println!();
println!("{:?}", only_err(vec![Ok(()), Ok(()), Ok(())]));
println!("{:?}", only_err(vec![Ok(()), Err(1), Err(2)]));
Ok([1, 2, 3]) Err(2) Ok(()) Err(1)
fn batch(v: Vec>) -> Result, u32> {
    v.into_iter().collect()
}

fn only_err(v: Vec>) -> Result<(), u32> {
    v.into_iter().collect()
}

fn main() {
println!("{:?}", batch(vec![Ok(1), Ok(2), Ok(3)]));
println!("{:?}", batch(vec![Ok(1), Err(2), Err(3)]));
println!();
println!("{:?}", only_err(vec![Ok(()), Ok(()), Ok(())]));
println!("{:?}", only_err(vec![Ok(()), Err(1), Err(2)]));
}

Итератори

Адаптери

Преди да правите сложни цикли за трансформация, разгледайте Iterator, FromIterator и IntoIterator.

Closures

Closures

syntax

1 2 3
|x: u32| -> u32 { x + 1 }
|x| { x + 1 }
|x| x + 1

Closure vs fn

Каква е разликата между функция и closure?

Closures могат да използват променливи дефинирани по-горе в scope-a.

1 2 3 4 5
fn main() {
    let other = String::from("foo");               // <-+
                                                   //   |
    Some("bar").map(|s| s.len() + other.len());    // --+
}
fn main() {
    let other = String::from("foo");               // <-+
                                                   //   |
    Some("bar").map(|s| s.len() + other.len());    // --+
}

Вътрешна имплементация

Зад кулисите компилаторът създава една структура и една функция

1 2 3 4 5 6 7 8 9 10 11
/// Структура в която запомняме променливите, които сме прихванали
struct State {
    other: String,
}

impl State {
    /// Функция която съдържа логиката
    fn call(&self, s: &str) -> usize {
        s.len() + self.other.len()
    }
}
#![allow(dead_code)]
fn main() {}
/// Структура в която запомняме променливите, които сме прихванали
struct State {
    other: String,
}

impl State {
    /// Функция която съдържа логиката
    fn call(&self, s: &str) -> usize {
        s.len() + self.other.len()
    }
}

Вътрешна имплементация

Как бихме използвали нашата имплементация

1 2 3 4 5 6 7 8 9 10 11 12
fn map_option(opt: Option<&str>, f: State) -> Option<usize> {
    match opt {
        Some(s) => Some(f.call(s)),
        None => None,
    }
}

fn main() {
    let other = String::from("foo");

    map_option(Some("bar"), State { other });
}
#![allow(dead_code)]
struct State {
other: String,
}
impl State {
fn call(&self, s: &str) -> usize {
s.len() + self.other.len()
}
}
fn map_option(opt: Option<&str>, f: State) -> Option {
    match opt {
        Some(s) => Some(f.call(s)),
        None => None,
    }
}

fn main() {
    let other = String::from("foo");

    map_option(Some("bar"), State { other });
}

Move closure

Closure-ите, за разлика от нашата имплементация, не консумират прихванатите променливи по подразбиране

1 2 3 4 5 6 7
let other = String::from("foo");

println!("{:?}", Some("bar").map(|s| s.len() + other.len()));
println!("{:?}", other);       // Ок

println!("{:?}", map_option(Some("bar"), State { other }));
// println!("{:?}", other);    // комп. грешка - use of moved value `other`
Some(6) "foo" Some(6)
#![allow(dead_code)]
struct State {
other: String,
}
impl State {
fn call(&self, s: &str) -> usize {
s.len() + self.other.len()
}
}
fn map_option(opt: Option<&str>, f: State) -> Option {
match opt {
Some(s) => Some(f.call(s)),
None => None,
}
}
fn main() {
let other = String::from("foo");

println!("{:?}", Some("bar").map(|s| s.len() + other.len()));
println!("{:?}", other);       // Ок

println!("{:?}", map_option(Some("bar"), State { other }));
// println!("{:?}", other);    // комп. грешка - use of moved value `other`
}

Move closure

Можем да променим семантиката с ключовата дума move

1 2 3 4 5 6
|s| s.len() + other.len();

// генерира
struct State<'a> {
    other: &'a String
}

1 2 3 4 5 6
move |s| s.len() + other.len();

// генерира
struct State {
    other: String
}

Move closure

move премества стойността, независимо как се използва

1 2 3 4 5 6 7 8
let nums = vec![0, 1, 2, 3];

// прихваща `nums` като `Vec<i32>`
let f = move || {
    for n in &nums {
        println!("{}", n);
    }
};
fn main() {
let nums = vec![0, 1, 2, 3];

// прихваща `nums` като `Vec`
let f = move || {
    for n in &nums {
        println!("{}", n);
    }
};
}

Move closure

Ако искаме да преместим някоя стойност, но да прихванем друга по референция:

1 2 3 4 5 6 7 8 9 10 11 12
let nums = vec![0, 1, 2, 3];
let s = String::from("cookies");

let f = || {
    // move `nums`
    let nums = nums;

    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", s);

"cookies"

fn main() {
let nums = vec![0, 1, 2, 3];
let s = String::from("cookies");

let f = || {
    // move `nums`
    let nums = nums;

    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", s);
}

1 2 3 4 5 6 7 8 9 10 11 12
let nums = vec![0, 1, 2, 3];
let s = String::from("cookies");

let f = || {
    // move `nums`
    let nums = nums;

    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", nums);

error[E0382]: borrow of moved value: `nums` --> src/bin/main_81dc119f3e90ee303c7ebd23dc742d4904615a0d.rs:13:18 | 2 | let nums = vec![0, 1, 2, 3]; | ---- move occurs because `nums` has type `Vec<i32>`, which does not implement the `Copy` trait ... 5 | let f = || { | -- value moved into closure here 6 | // move `nums` 7 | let nums = nums; | ---- variable moved due to use in closure ... 13 | println!("{:?}", nums); | ^^^^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` due to previous error

fn main() {
let nums = vec![0, 1, 2, 3];
let s = String::from("cookies");

let f = || {
    // move `nums`
    let nums = nums;

    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", nums);
}

Move closure

Или с move closure:

1 2 3 4 5 6 7 8 9
let nums = vec![0, 1, 2, 3];
let s = &String::from("cookies");

let f = move || {
    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", s);

"cookies"

fn main() {
let nums = vec![0, 1, 2, 3];
let s = &String::from("cookies");

let f = move || {
    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", s);
}

1 2 3 4 5 6 7 8 9
let nums = vec![0, 1, 2, 3];
let s = &String::from("cookies");

let f = move || {
    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", nums);

error[E0382]: borrow of moved value: `nums` --> src/bin/main_b7a8fdf6144b10d7b7ab47e78a1d1fd812793364.rs:10:18 | 2 | let nums = vec![0, 1, 2, 3]; | ---- move occurs because `nums` has type `Vec<i32>`, which does not implement the `Copy` trait ... 5 | let f = move || { | ------- value moved into closure here 6 | println!("{:?}", nums); | ---- variable moved due to use in closure ... 10 | println!("{:?}", nums); | ^^^^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` due to previous error

fn main() {
let nums = vec![0, 1, 2, 3];
let s = &String::from("cookies");

let f = move || {
    println!("{:?}", nums);
    println!("{:?}", s);
};

println!("{:?}", nums);
}

Disjoint capture

Ако имаме някакви композитни данни като структура или кортеж, тогава Rust позволява да се прихванат само част от данните.

1 2 3 4 5
let x = (vec![0], vec![0]);
let c = move || {
    // Само `x.0` се прихваща
    println!("{:?}", x.0);
};
#![allow(unused_variables)]
fn main() {
let x = (vec![0], vec![0]);
let c = move || {
    // Само `x.0` се прихваща
    println!("{:?}", x.0);
};
}

Disjoint capture

Може да накараме компилатора да прихване цялата стойност с присвояване.

1 2 3 4 5 6
let x = (vec![0], vec![0]);
let c = move || {
    let _ = &x;

    println!("{:?}", x.0);
};
#![allow(unused_variables)]
fn main() {
let x = (vec![0], vec![0]);
let c = move || {
    let _ = &x;

    println!("{:?}", x.0);
};
}

Drop order

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
{
    let x = (vec![0], vec![0]);

    {
        let c = || {
            // Rust 2018 прихваща цялата `x`
            // Rust 2021 прихваща само `x.0`
            move_value(x.0);
        };

        // В Rust 2018 `c` и `x` се дропват на края на блока.
        // В Rust 2021 `c` и `x.0` се дропват на края на блока.
    }

    // В Rust 2018 стойността на `x` е преместена, затова не се дропва тук.
    // В Rust 2021 стойността на `x.0` е била дропната,
    // но стойносттна на `x.1` се дропва тук.
}
#![allow(unused_variables)]
fn move_value(val: T) {}
fn main() {
{
    let x = (vec![0], vec![0]);

    {
        let c = || {
            // Rust 2018 прихваща цялата `x`
            // Rust 2021 прихваща само `x.0`
            move_value(x.0);
        };

        // В Rust 2018 `c` и `x` се дропват на края на блока.
        // В Rust 2021 `c` и `x.0` се дропват на края на блока.
    }

    // В Rust 2018 стойността на `x` е преместена, затова не се дропва тук.
    // В Rust 2021 стойността на `x.0` е била дропната,
    // но стойносттна на `x.1` се дропва тук.
}
}

Fn traits

Fn traits

Имат специален синтаксис, например

Fn traits

FnOnce

1 2 3 4 5
// опростено
trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

Fn traits

FnOnce

1 2 3 4 5
// опростено
trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

Fn traits

FnOnce

1 2 3 4 5
// опростено
trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

Fn traits

FnOnce

1 2 3 4 5
// опростено
trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

Fn traits

FnOnce

1 2 3 4 5
// опростено
trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

Fn traits

FnOnce

1 2 3 4 5
// опростено
trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

Fn traits

FnMut

1 2 3 4
// опростено
trait FnMut<Args>: FnOnce<Args> {
    fn call_mut(&mut self, args: Args) -> Self::Output;
}

Fn traits

FnMut

1 2 3 4
// опростено
trait FnMut<Args>: FnOnce<Args> {
    fn call_mut(&mut self, args: Args) -> Self::Output;
}

Fn traits

FnMut

1 2 3 4
// опростено
trait FnMut<Args>: FnOnce<Args> {
    fn call_mut(&mut self, args: Args) -> Self::Output;
}

Fn traits

Fn

1 2 3 4
// опростено
trait Fn<Args>: FnMut<Args> {
    fn call(&self, args: Args) -> Self::Output;
}

Fn traits

Fn

1 2 3 4
// опростено
trait Fn<Args>: FnMut<Args> {
    fn call(&self, args: Args) -> Self::Output;
}

Fn traits

Fn

1 2 3 4
// опростено
trait Fn<Args>: FnMut<Args> {
    fn call(&self, args: Args) -> Self::Output;
}

Fn traits

Fn

1 2 3 4
// опростено
trait Fn<Args>: FnMut<Args> {
    fn call(&self, args: Args) -> Self::Output;
}

Fn traits

Когато създадем closure, компилатора имплементира всички trait-ове, които може

Fn traits

Когато създадем closure, компилатора имплементира всички trait-ове, които може

Fn traits

Когато създадем closure, компилатора имплементира всички trait-ове, които може

Fn traits

Когато създадем closure, компилатора имплементира всички trait-ове, които може

Fn traits

Когато създадем closure, компилатора имплементира всички trait-ове, които може

Fn traits

Когато създадем closure, компилатора имплементира всички trait-ове, които може

Taking closures

По-популярния начин за взимане на closure е чрез static dispatch

1 2 3 4 5
fn eval_and_increment<F>(f: F) -> usize where F: Fn???() -> usize {
    f() + 1
}

println!("{}", eval_and_increment(|| 1));

Taking closures

Кой Fn trait да сложим за ограничение?

Тип Прихващане на стойности Брой викания Кога?
FnOnce може да местим, променяме и четем стойности веднъж move closures
FnMut може да променяме и четем стойности множество пъти викане множество пъти
Fn може да четем стойности множество пъти когато не можем да прихванем &mut референция

Taking closures

Кой Fn trait да сложим за ограничение?

Тип Прихващане на стойности Брой викания Кога?
FnOnce може да местим, променяме и четем стойности веднъж move closures
FnMut може да променяме и четем стойности множество пъти викане множество пъти
Fn може да четем стойности множество пъти когато не можем да прихванем &mut референция

или пробваме в този ред докато компилаторът ни разреши 😉

Taking closures

1 2 3 4 5
fn eval_and_increment<F>(f: F) -> usize where F: FnOnce() -> usize {
    f() + 1
}

println!("{}", eval_and_increment(|| 1));
2
fn eval_and_increment(f: F) -> usize where F: FnOnce() -> usize {
    f() + 1
}

fn main() {
println!("{}", eval_and_increment(|| 1));
}

Taking closures

Ако closure не прихваща нищо, той се свежда до функция

1 2 3 4 5
fn eval_and_increment(f: fn() -> usize) -> usize {
    f() + 1
}

println!("{}", eval_and_increment(|| 1));
2
fn eval_and_increment(f: fn() -> usize) -> usize {
    f() + 1
}

fn main() {
println!("{}", eval_and_increment(|| 1));
}

Taking closures

Може да подаваме функции, където се очаква closure

1 2 3 4 5 6 7 8 9
fn one() -> usize {
    1
}

fn eval_and_increment<F>(f: F) -> usize where F: FnOnce() -> usize {
    f() + 1
}

println!("{}", eval_and_increment(one));
2
fn one() -> usize {
    1
}

fn eval_and_increment(f: F) -> usize where F: FnOnce() -> usize {
    f() + 1
}

fn main() {
println!("{}", eval_and_increment(one));
}

Returning closures

impl Trait

Не знаем типа на closure-a тъй като се генерира при компилиране, съответно това е един начин за връщане на closure

1 2 3 4 5
fn curry(a: u32) -> impl Fn(u32) -> u32 {
    move |b| a + b
}

println!("{}", curry(1)(2));
3
fn curry(a: u32) -> impl Fn(u32) -> u32 {
    move |b| a + b
}

fn main() {
println!("{}", curry(1)(2));
}

impl Trait

Може да стои на мястото на типа на аргумент или return типа

1 2 3 4 5 6 7
use std::fmt::Debug;

fn id(arg: impl Debug) -> impl Debug {
    arg
}
println!("{:?}", id(1));
println!("{:?}", id("foo"));
1 "foo"
use std::fmt::Debug;

fn id(arg: impl Debug) -> impl Debug {
    arg
}
fn main() {
println!("{:?}", id(1));
println!("{:?}", id("foo"));
}

impl Trait

Не може да правите нищо друго с него освен това което имплементира

1 2 3 4 5 6
use std::fmt::Debug;

fn id(arg: impl Debug) -> impl Debug {
    arg
}
println!("{}", id(1));
error[E0277]: `impl Debug` doesn't implement `std::fmt::Display` --> src/bin/main_8bf7039ea5b999af5f79cbab4e653a034da9476d.rs:7:16 | 7 | println!("{}", id(1)); | ^^^^^ `impl Debug` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `impl Debug` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0277`. error: could not compile `rust` due to previous error
use std::fmt::Debug;

fn id(arg: impl Debug) -> impl Debug {
    arg
}
fn main() {
println!("{}", id(1));
}

impl Trait

Удобно е за връщане на итератори

1 2 3 4 5 6 7 8 9 10 11
use std::fmt::Debug;

fn create_iter() -> impl Iterator<Item = impl Debug> {
    vec![0, 1, 2].into_iter().map(|x| x * 2).enumerate()
}

fn main() {
    for x in create_iter() {
        println!("{:?}", x);
    }
}
(0, 0) (1, 2) (2, 4)
use std::fmt::Debug;

fn create_iter() -> impl Iterator {
    vec![0, 1, 2].into_iter().map(|x| x * 2).enumerate()
}

fn main() {
    for x in create_iter() {
        println!("{:?}", x);
    }
}

impl Trait

Разликата между generics и impl Trait

Въпроси