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

7 ноември 2024

Преговор

Преговор

Преговор

Преговор

Преговор

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

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

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

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

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

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

Списък

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);
}

Drop

Имплементацията на std::mem::drop

1
pub fn drop<T>(_x: T) {}

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

Display

Display

Display

Display

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

struct MagicTrick {
    description: String,
    secrets: Vec<String>,
    skills: Vec<String>,
}

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

struct MagicTrick {
    description: String,
    secrets: Vec,
    skills: Vec,
}

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

Display

Макрос write

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

Display

Макрос write

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

Display

Макрос write

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

Display

Макрос write

1
write!(f, "Магически трик {:?}", self.description)
1 2
// разгръща се до
f.write_fmt(format_args!("Магически трик {:?}", self.description))

Debug

Debug

Debug

Debug

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#[derive(Debug)]
struct MagicTrick {
    description: String,
    secrets: Vec<String>,
    skills: Vec<String>,
}

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

    println!("{:?}", trick);
}
MagicTrick { description: "Изчезваща монета", secrets: ["Монетата се прибира в ръкава"], skills: ["Бързи ръце", "Заблуда"] }
#[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);
}

Debug

Formatter структура

Debug

Formatter структура

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 {
        f.debug_struct("Трик")
            .field("описание", &self.description)
            .field("тайни", &self.secrets)
            .field("умения", &self.skills)
            .finish()
    }
}

fn main() {
    let trick = MagicTrick { /* ... */ };
    println!("{:?}", trick);
}
Трик { описание: "Изчезваща монета", тайни: ["Монетата се прибира в ръкава"], умения: ["Бързи ръце", "Заблуда"] }
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 {
        f.debug_struct("Трик")
            .field("описание", &self.description)
            .field("тайни", &self.secrets)
            .field("умения", &self.skills)
            .finish()
    }
}

fn main() {
/*
    let trick = MagicTrick { /* ... */ };
*/
let trick = MagicTrick {
description: String::from("Изчезваща монета"),
secrets: vec![String::from("Монетата се прибира в ръкава")],
skills: vec![String::from("Бързи ръце"), String::from("Заблуда")],
};
    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 6
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 6
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 6
trait PartialEq<Rhs = Self>
where Rhs: ?Sized
{
    fn eq(&self, other: &Rhs) -> bool;
    fn ne(&self, other: &Rhs) -> bool { ... }
}
1
assert_eq!(f64::NAN == f64::NAN, false);

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

PartialEq

1 2 3 4 5 6
trait PartialEq<Rhs = Self>
where Rhs: ?Sized
{
    fn eq(&self, other: &Rhs) -> bool;
    fn ne(&self, other: &Rhs) -> bool { ... }
}
1
assert_eq!(f64::NAN == f64::NAN, false);
warning: incorrect NaN comparison, NaN cannot be directly compared to itself --> src/bin/main_67b4f7e90fa6410e6b5325ec4fb8eb835bf62969.rs:2:16 | 2 | assert_eq!(f64::NAN == f64::NAN, false); | ^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(invalid_nan_comparisons)]` on by default help: use `f32::is_nan()` or `f64::is_nan()` instead | 2 - assert_eq!(f64::NAN == f64::NAN, false); 2 + assert_eq!(f64::NAN.is_nan(), false); |
fn main() {
    assert_eq!(f64::NAN == f64::NAN, false);
}

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

Eq

1
trait Eq: PartialEq<Self> { }

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

Eq

1
trait Eq: PartialEq<Self> { }

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

Eq

1
trait Eq: PartialEq<Self> { }

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

Eq

1
trait Eq: PartialEq<Self> { }

trait Eq: PartialEq<Self> означава, че Eq e subtrait на PartialEq<Self>.
За да имплементираме Eq за T, трябва да има имплементация на PartialEq<T> за T.

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

PartialOrd

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
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!(f64::NAN < 0.0, false);
assert_eq!(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 е изпълнено.

Closures

Closures

синтаксис

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

Closures

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()
    }
}
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 });
}

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

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`
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`
}

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

Всъщност имплементацията изглежда така

1 2 3 4 5 6 7 8 9
struct State<'a> {
    other: &'a String,
}

impl<'a> State<'a> {
    fn call(&self, s: &str) -> usize {
        s.len() + self.other.len()
    }
}
fn main() {}
struct State<'a> {
    other: &'a String,
}

impl<'a> State<'a> {
    fn call(&self, s: &str) -> usize {
        s.len() + self.other.len()
    }
}

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

Всъщност и това не е вярно.
Ако променливата се използва зад референция, ще я прихване по референция

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

let f = || {
    for n in nums.iter() {  // Vec::iter(&self)
        println!("{}", n);  // ==> прихваща nums като &Vec<i32>
    }
};

f();
println!("{:?}", nums);
1 2 3 [1, 2, 3]
fn main() {
let nums = vec![1, 2, 3];

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

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

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

..
Ако променливата се използва по стойност, ще се премести в анонимната функция

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

let f = || {
    for n in nums.into_iter() { // Vec::into_iter(self)
        println!("{}", n);      //  ==> прихваща nums като Vec<i32>
    }
};

f();
// println!("{:?}", nums);
1 2 3
fn main() {
let nums = vec![1, 2, 3];

let f = || {
    for n in nums.into_iter() { // Vec::into_iter(self)
        println!("{}", n);      //  ==> прихваща nums като Vec
    }
};

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

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

..
Ако променливата се използва по стойност, ще се премести в анонимната функция

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

let f = || {
    for n in nums.into_iter() { // Vec::into_iter(self)
        println!("{}", n);      // ==> прихваща nums като Vec<i32>
    }
};

f();
println!("{:?}", nums);
error[E0382]: borrow of moved value: `nums` --> src/bin/main_46965ba87cdce000f98685440ed7123d92fee21a.rs:11:18 | 2 | let nums = vec![1, 2, 3]; | ---- move occurs because `nums` has type `Vec<i32>`, which does not implement the `Copy` trait 3 | 4 | let f = || { | -- value moved into closure here 5 | for n in nums.into_iter() { // Vec::into_iter(self) | ---- variable moved due to use in closure ... 11 | 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) help: consider cloning the value if the performance cost is acceptable | 5 | for n in nums.clone().into_iter() { // Vec::into_iter(self) | ++++++++ For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_46965ba87cdce000f98685440ed7123d92fee21a") due to 1 previous error
fn main() {
let nums = vec![1, 2, 3];

let f = || {
    for n in nums.into_iter() { // Vec::into_iter(self)
        println!("{}", n);      // ==> прихваща nums като Vec
    }
};

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

Move closure

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

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

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

println!("{:?}", Some("bar").map(move |s| s.len() + other.len()));
// println!("{:?}", other);   // грешка: use of moved value: `other`
fn main() {
let other = String::from("foo");

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

println!("{:?}", Some("bar").map(move |s| s.len() + other.len()));
// println!("{:?}", other);   // грешка: use of moved value: `other`
}

Move closure

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

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

// генерира
struct State<'a> {
    other: &'a String
}
1 2 3 4 5 6
let closure = move |s| s.len() + other.len();

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

Move closure

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

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

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

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

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

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

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

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

Move closure

Друг вариант, използвайки move closure

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

let f = {
    let cookies_ref = &cookies; // ще премести `cookies_ref` във функцията,
                                // но типа на `cookies_ref` е `&String`

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

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

let f = {
    let cookies_ref = &cookies; // ще премести `cookies_ref` във функцията,
                                // но типа на `cookies_ref` е `&String`

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

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

Move closure

Друг вариант, използвайки move closure

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

let f = {
    let cookies = &cookies;     // ще премести `cookies` във функцията,
                                // но типа на `cookies` е `&String`

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

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

let f = {
    let cookies = &cookies;     // ще премести `cookies` във функцията,
                                // но типа на `cookies` е `&String`

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

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

Closures като аргументи

Closures като аргументи

Как да подадем анонимна функция като аргумент?

1 2 3 4 5 6
fn map_option(opt: Option<&str>, f: ???) -> Option<u32> {
    match opt {
        Some(s) => Some(f(s)),
        None => None,
    }
}

Closures като аргументи

Как да подадем анонимна функция като аргумент?

1 2 3 4 5 6 7 8 9
fn map_option<F>(opt: Option<&str>, f: F) -> Option<u32>
where
    F: FnOnce(&str) -> u32,
{
    match opt {
        Some(s) => Some(f(s)),
        None => None,
    }
}
fn main() {}
fn map_option(opt: Option<&str>, f: F) -> Option
where
    F: FnOnce(&str) -> u32,
{
    match opt {
        Some(s) => Some(f(s)),
        None => None,
    }
}

Fn traits

Fn traits

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

Fn traits

1 2 3 4 5 6 7 8 9 10 11 12
trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

trait FnMut<Args> : FnOnce<Args> {
    fn call_mut(&mut self, args: Args) -> Self::Output;
}

trait Fn<Args> : FnMut<Args> {
    fn call(&self, args: Args) -> Self::Output;
}

Fn traits

Fn

Fn traits

Fn

Fn traits

Fn

Fn traits

FnMut

Fn traits

FnMut

Fn traits

FnMut

Fn traits

FnMut

Fn traits

FnMut

Пример - функция, която си променя състоянието

1 2 3 4 5 6 7 8 9 10
let mut counter = 0;

let mut f = move || {
    counter += 1;
    counter
};

println!("{}", f());
println!("{}", f());
println!("{}", f());
1 2 3
fn main() {
let mut counter = 0;

let mut f = move || {
    counter += 1;
    counter
};

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

Fn traits

FnMut

Пример - функция, която променя външна прихваната променлива

1 2 3 4 5 6 7 8 9 10
let mut buffer = String::new();

let mut f = |text| {
    buffer.push_str(text);
    buffer.len()
};

println!("{}", f("foo"));
println!("{}", f("bar"));
println!("{}", buffer);
3 6 foobar
fn main() {
let mut buffer = String::new();

let mut f = |text| {
    buffer.push_str(text);
    buffer.len()
};

println!("{}", f("foo"));
println!("{}", f("bar"));
println!("{}", buffer);
}

Fn traits

FnOnce

Fn traits

FnOnce

Fn traits

FnOnce

Fn traits

FnOnce

Пример

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

let f = || {
    for n in nums.into_iter() {
        println!("{}", n);
    }
};

f();
// f();
1 2 3
fn main() {
let nums = vec![1, 2, 3];

let f = || {
    for n in nums.into_iter() {
        println!("{}", n);
    }
};

f();
// f();
}

Fn traits

FnOnce

Пример

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

let f = || {
    for n in nums.into_iter() {
        println!("{}", n);
    }
};

f();
f();
error[E0382]: use of moved value: `f` --> src/bin/main_faa575e42fe03f0ba26536c5ae8d02ab15c81572.rs:11:1 | 10 | f(); | --- `f` moved due to this call 11 | f(); | ^ value used here after move | note: closure cannot be invoked more than once because it moves the variable `nums` out of its environment --> src/bin/main_faa575e42fe03f0ba26536c5ae8d02ab15c81572.rs:5:14 | 5 | for n in nums.into_iter() { | ^^^^ note: this value implements `FnOnce`, which causes it to be moved when called --> src/bin/main_faa575e42fe03f0ba26536c5ae8d02ab15c81572.rs:10:1 | 10 | f(); | ^ For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_faa575e42fe03f0ba26536c5ae8d02ab15c81572") due to 1 previous error
fn main() {
let nums = vec![1, 2, 3];

let f = || {
    for n in nums.into_iter() {
        println!("{}", n);
    }
};

f();
f();
}

Fn traits

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

Fn traits

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

Fn traits

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

Fn traits

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

Fn traits

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

Защо?

Fn traits

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

Защо?

Fn traits

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

Защо?

Fn traits

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

Защо?

Fn traits

Кои трейтове да използваме?

Fn traits

Кои трейтове да използваме?

Ако приемаме closure като аргумент:

Fn traits

Кои трейтове да използваме?

Ако приемаме closure като аргумент:

Ако връщаме closure:

fn и Fn

fn и Fn

1
fn repeat(c: char, count: u32) -> String { /*...*/ }
error[E0601]: `main` function not found in crate `main_732470937c391955b0bf4cfefbf788cc52fa92d9` --> src/bin/main_732470937c391955b0bf4cfefbf788cc52fa92d9.rs:1:53 | 1 | fn repeat(c: char, count: u32) -> String { /*...*/ } | ^ consider adding a `main` function to `src/bin/main_732470937c391955b0bf4cfefbf788cc52fa92d9.rs` error[E0308]: mismatched types --> src/bin/main_732470937c391955b0bf4cfefbf788cc52fa92d9.rs:1:35 | 1 | fn repeat(c: char, count: u32) -> String { /*...*/ } | ------ ^^^^^^ expected `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression Some errors have detailed explanations: E0308, E0601. For more information about an error, try `rustc --explain E0308`. error: could not compile `rust` (bin "main_732470937c391955b0bf4cfefbf788cc52fa92d9") due to 2 previous errors
fn repeat(c: char, count: u32) -> String { /*...*/ }

fn и Fn

fn типовете имплементират всички Fn traits

Closures, които не прихващат нищо, могат да се конвертират до fn тип

1
let add_one: fn(u32) -> u32 = |x| x + 1;
fn main() {
let add_one: fn(u32) -> u32 = |x| x + 1;
}

Closures като резултат

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

1 2 3 4 5 6 7
fn make_auto_incrementer() -> ??? {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}

Closures като резултат

Конкретен тип?

1 2 3 4 5 6 7
fn make_auto_incrementer() -> ??? {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}

Closures като резултат

Generic тип?

1 2 3 4 5 6 7
fn make_auto_incrementer<F: FnMut() -> u32>() -> F {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}
error[E0308]: mismatched types --> src/bin/main_b611835db2c98592b33556b63109ccc642e8c41c.rs:5:5 | 3 | fn make_auto_incrementer<F: FnMut() -> u32>() -> F { | - - | | | | | expected `F` because of return type | | help: consider using an impl return type: `impl FnMut() -> u32` | expected this type parameter 4 | let mut counter = 0; 5 | / move || { 6 | | counter += 1; 7 | | counter 8 | | } | |_____^ expected type parameter `F`, found closure | = note: expected type parameter `F` found closure `{closure@src/bin/main_b611835db2c98592b33556b63109ccc642e8c41c.rs:5:5: 5:12}` = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F` For more information about this error, try `rustc --explain E0308`. error: could not compile `rust` (bin "main_b611835db2c98592b33556b63109ccc642e8c41c") due to 1 previous error
fn main() {}
fn make_auto_incrementer u32>() -> F {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}

Closures като резултат

Trait object

1 2 3 4 5 6 7
fn make_auto_incrementer() -> Box<dyn FnMut() -> u32> {
    let mut counter = 0;
    Box::new(move || {
        counter += 1;
        counter
    })
}
fn make_auto_incrementer() -> Box u32> {
    let mut counter = 0;
    Box::new(move || {
        counter += 1;
        counter
    })
}
fn main() {}

Closures като резултат

Trait object

1 2 3 4 5 6 7 8 9 10 11 12 13 14
fn make_auto_incrementer() -> Box<dyn FnMut() -> u32> {
    let mut counter = 0;
    Box::new(move || {
        counter += 1;
        counter
    })
}

fn main() {
    let mut inc = make_auto_incrementer();
    println!("{}", inc());
    println!("{}", inc());
    println!("{}", inc());
}
1 2 3
fn make_auto_incrementer() -> Box u32> {
    let mut counter = 0;
    Box::new(move || {
        counter += 1;
        counter
    })
}

fn main() {
    let mut inc = make_auto_incrementer();
    println!("{}", inc());
    println!("{}", inc());
    println!("{}", inc());
}

Closures като резултат

impl Trait

1 2 3 4 5 6 7
fn make_auto_incrementer() -> impl FnMut() -> u32 {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}
fn make_auto_incrementer() -> impl FnMut() -> u32 {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}
fn main() {}

Closures като резултат

impl Trait

1 2 3 4 5 6 7 8 9 10 11 12 13 14
fn make_auto_incrementer() -> impl FnMut() -> u32 {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}

fn main() {
    let mut inc = make_auto_incrementer();
    println!("{}", inc());
    println!("{}", inc());
    println!("{}", inc());
}
1 2 3
fn make_auto_incrementer() -> impl FnMut() -> u32 {
    let mut counter = 0;
    move || {
        counter += 1;
        counter
    }
}

fn main() {
    let mut inc = make_auto_incrementer();
    println!("{}", inc());
    println!("{}", inc());
    println!("{}", inc());
}

impl Trait

като резултат

1
fn make_auto_incrementer() -> impl FnMut() -> u32 { /*...*/ }

impl Trait

като резултат

1
fn make_auto_incrementer() -> impl FnMut() -> u32 { /*...*/ }

impl Trait

като резултат

1
fn make_auto_incrementer() -> impl FnMut() -> u32 { /*...*/ }

impl Trait

като резултат

1
fn make_auto_incrementer() -> impl FnMut() -> u32 { /*...*/ }

impl Trait

като резултат

Удобно за използване, когато:

impl Trait

като резултат

Удобно за използване, когато:

impl Trait

като резултат

Удобно за използване, когато:

impl Trait

като резултат

Удобно за използване, когато:

impl Trait

като аргумент

impl Trait може да се напише и в позицията на аргумент.
Тогава е (почти) еквивалнтен на generic параметър.

1 2 3 4 5 6 7
fn print1(t: impl Display) {
    println!("{}", t);
}

fn print2<T: Display>(t: T) {
    println!("{}", t);
}
fn main() {}
use std::fmt::Display;
fn print1(t: impl Display) {
    println!("{}", t);
}

fn print2(t: T) {
    println!("{}", t);
}

impl Trait

като аргумент

impl Trait може да се напише и в позицията на аргумент.
Тогава е (почти) еквивалнтен на generic параметър.

1 2 3 4 5 6 7
fn print1(t: impl Display) {
    println!("{}", t);
}

fn print2<T: Display>(t: T) {
    println!("{}", t);
}
fn main() {}
use std::fmt::Display;
fn print1(t: impl Display) {
    println!("{}", t);
}

fn print2(t: T) {
    println!("{}", t);
}

Въпроси