Generics & traits I

Шаблонни типове и типажи

28 октомври 2025

Преговор

Generics

функции

Позволяват да пишем код, валиден за различни ситуации

1 2 3 4 5 6 7
fn identity_i32(value: i32) -> i32 {
    value
}

fn identity_i8(value: u8) -> u8 {
    value
}
fn main() {}
fn identity_i32(value: i32) -> i32 {
    value
}

fn identity_i8(value: u8) -> u8 {
    value
}

Generics

функции

Позволяват да пишем код, валиден за различни ситуации

1 2 3
fn identity<T>(value: T) -> T {
    value
}
fn main() {}
fn identity(value: T) -> T {
    value
}

Generics

функции

Можем да пишем по-сложни функции..

1 2 3
fn sum<T>(a: T, b: T) -> T {
    a + b
}

Generics

функции

Можем да пишем по-сложни функции.. ама всъщност не

1 2 3
fn sum<T>(a: T, b: T) -> T {
    a + b
}
error[E0369]: cannot add `T` to `T` --> src/bin/main_ac0e659fcafa1345b52e1d46ce02b96c1d43fbfb.rs:4:7 | 4 | a + b | - ^ - T | | | T | help: consider restricting type parameter `T` with trait `Add` | 3 | fn sum<T: std::ops::Add<Output = T>>(a: T, b: T) -> T { | +++++++++++++++++++++++++++ For more information about this error, try `rustc --explain E0369`. error: could not compile `rust` (bin "main_ac0e659fcafa1345b52e1d46ce02b96c1d43fbfb") due to 1 previous error
fn main() {}
fn sum(a: T, b: T) -> T {
    a + b
}

Generics

функции

1 2 3
// C++
template<class T>
const T& max(const T& a, const T& b);

Generics

функции

1 2 3
// C++
template<class T>
const T& max(const T& a, const T& b);

Generics

функции

1 2 3
// C++
template<class T>
const T& max(const T& a, const T& b);

Generics

функции

1 2 3
// C++
template<class T>
const T& max(const T& a, const T& b);

Generics

функции

1 2 3
fn sum<T>(a: T, b: T) -> T {
    a + b
}

Generics

функции

1 2 3
fn sum<T>(a: T, b: T) -> T {
    a + b
}

Generics

функции

1 2 3
fn sum<T>(a: T, b: T) -> T {
    a + b
}

Generics

функции

1 2 3
fn sum<T>(a: T, b: T) -> T {
    a + b
}

Generics

функции

Generics

функции

Generics

функции

1 2 3 4 5 6 7 8 9 10
use std::ops::Add;

fn sum<T: Add<Output=T>>(a: T, b: T) -> T {
    a + b
}

fn main() {
    println!("{:?}", sum(1, 2));
    println!("{:?}", sum(10.5, 11.3));
}
3 21.8
use std::ops::Add;

fn sum>(a: T, b: T) -> T {
    a + b
}

fn main() {
    println!("{:?}", sum(1, 2));
    println!("{:?}", sum(10.5, 11.3));
}

Generics

структури

1 2 3 4 5 6 7 8 9 10 11 12
struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    // Може да я създадем с цели числа
    let integer = Point { x: 5, y: 10 };

    // или с числа с плаваща запетая.
    let float = Point { x: 1.0, y: 4.0 };
}
struct Point {
    x: T,
    y: T,
}

fn main() {
    // Може да я създадем с цели числа
    let integer = Point { x: 5, y: 10 };

    // или с числа с плаваща запетая.
    let float = Point { x: 1.0, y: 4.0 };
}

Generics

структури

Ако искаме да позволим двете координати да са различни типове

1 2 3 4 5 6 7 8 9 10
struct Point<T, U> {
    x: T,
    y: U,
}

fn main() {
    let both_integer = Point { x: 5, y: 10 };
    let both_float = Point { x: 1.0, y: 4.0 };
    let integer_and_string = Point { x: 5, y: "4.0" };
}
struct Point {
    x: T,
    y: U,
}

fn main() {
    let both_integer = Point { x: 5, y: 10 };
    let both_float = Point { x: 1.0, y: 4.0 };
    let integer_and_string = Point { x: 5, y: "4.0" };
}

Generics

енумерации

1 2 3 4 5 6 7 8 9
enum Message<T, A> {
    Text(T),
    Action(A),
}

enum Option<T> {
    Some(T),
    None,
}
fn main() {}
enum Message {
    Text(T),
    Action(A),
}

enum Option {
    Some(T),
    None,
}

Generics

методи

1 2 3 4 5 6 7 8 9 10 11 12 13
struct Point<T> { x: T, y: T }

// Забележете impl<T>
impl<T> Point<T> {
    fn coords(&self) -> (&T, &T) {
        (&self.x, &self.y)
    }
}

fn main() {
    let p = Point { x: 5, y: 10 };
    println!("coords = {:?}", p.coords());
}
coords = (5, 10)
struct Point { x: T, y: T }

// Забележете impl
impl Point {
    fn coords(&self) -> (&T, &T) {
        (&self.x, &self.y)
    }
}

fn main() {
    let p = Point { x: 5, y: 10 };
    println!("coords = {:?}", p.coords());
}

Generics

методи

impl<T> Point<T> { ... }

означава

за всяко Т: impl Point<T> { ... }

Generics

специализирани impl блокове

1 2 3 4 5 6 7 8 9 10 11 12 13
struct Point<T> { x: T, y: T }

// Този път няма impl<T>
impl Point<f32> {
    fn dist_from_origin(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

fn main() {
    println!("dist = {:?}", Point { x: 5.0, y: 10.0 }.dist_from_origin());
    // println!("dist = {:?}", Point { x: 5, y: 10 }.dist_from_origin());
}
struct Point { x: T, y: T }

// Този път няма impl
impl Point {
    fn dist_from_origin(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

fn main() {
    println!("dist = {:?}", Point { x: 5.0, y: 10.0 }.dist_from_origin());
    // println!("dist = {:?}", Point { x: 5, y: 10 }.dist_from_origin());
}

Generics

специализирани impl блокове

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
struct Point<T, U> { x: T, y: U }

// за всяко Т: impl Point<T, T>
impl<T> Point<T, T> {
    fn coords_1(&self) -> (&T, &T) {
        (&self.x, &self.y)
    }
}

// за всяко T, за всяко U: impl Point<T, U>
impl<T, U> Point<T, U> {
    fn coords_2(&self) -> (&T, &U) {
        (&self.x, &self.y)
    }
}
struct Point { x: T, y: U }

// за всяко Т: impl Point
impl Point {
    fn coords_1(&self) -> (&T, &T) {
        (&self.x, &self.y)
    }
}

// за всяко T, за всяко U: impl Point
impl Point {
    fn coords_2(&self) -> (&T, &U) {
        (&self.x, &self.y)
    }
}

fn main() {}

Generics

generic методи

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
struct Point<T, U> { x: T, y: U }

impl<T, U> Point<T, U> {
    // Създава нова структура с `x` от `self` и `y` от `other`.
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
        Point { x: self.x, y: other.y }
    }
}

fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c'};
    let p3 = p1.mixup(p2);
    println!("p3.x = {:?}", p3.x);
    println!("p3.y = {:?}", p3.y);
}
p3.x = 5 p3.y = 'c'
struct Point { x: T, y: U }

impl Point {
    // Създава нова структура с `x` от `self` и `y` от `other`.
    fn mixup(self, other: Point) -> Point {
        Point { x: self.x, y: other.y }
    }
}

fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c'};
    let p3 = p1.mixup(p2);
    println!("p3.x = {:?}", p3.x);
    println!("p3.y = {:?}", p3.y);
}

Const generics

1 2 3 4 5 6 7
fn f<T, const N: usize>(_a: [T; N]) { }

fn main() {
    f::<String, 1>([
        String::from("hello"),
    ]);
}
fn f(_a: [T; N]) { }

fn main() {
    f::([
        String::from("hello"),
    ]);
}

Упражнение

The JSON encoder

1 2 3
fn to_json<T>(val: T) -> String {
    ...
}

Упражнение

The JSON encoder

Тук възникват няколко въпроса:

Упражнение

The JSON encoder

Тук възникват няколко въпроса:

Типажи

Traits

Типажи

Traits

Типажи

Traits

Типажи

Traits

Типажи

Traits

Типажи

Traits

Типажи

Дефинираме си trait:

1 2 3
trait ToJson {
    fn to_json(&self) -> String;
}
fn main() {}
trait ToJson {
    fn to_json(&self) -> String;
}

The JSON encoder

Сега можем да го имплементираме за някои вградени типове данни:

1 2 3 4 5
impl ToJson for String {
    fn to_json(&self) -> String {
        format!("\"{}\"", self)
    }
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for String {
    fn to_json(&self) -> String {
        format!("\"{}\"", self)
    }
}

The JSON encoder

Сега можем да го имплементираме за някои вградени типове данни:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
impl ToJson for i32 {
    fn to_json(&self) -> String {
        format!("{}", self)
    }
}

impl ToJson for f32 {
    fn to_json(&self) -> String {
        format!("{}", self)
    }
}

impl ToJson for () {
    fn to_json(&self) -> String {
        "null".to_string()
    }
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for i32 {
    fn to_json(&self) -> String {
        format!("{}", self)
    }
}

impl ToJson for f32 {
    fn to_json(&self) -> String {
        format!("{}", self)
    }
}

impl ToJson for () {
    fn to_json(&self) -> String {
        "null".to_string()
    }
}

The JSON encoder

1 2 3
println!("String as json: {}", String::from("mama").to_json());

println!("Number as json: {}", 3.to_json());
String as json: "mama" Number as json: 3
trait ToJson {
fn to_json(&self) -> String;
}
impl ToJson for String {
fn to_json(&self) -> String {
format!(r#""{}""#, self)
}
}
impl ToJson for i32 {
fn to_json(&self) -> String {
format!("{}", self)
}
}
fn main() {
println!("String as json: {}", String::from("mama").to_json());

println!("Number as json: {}", 3.to_json());
}

The JSON encoder

Ограничения (trait bounds)

Още малко - за Option!

1 2 3 4 5 6 7 8
impl<T> ToJson for Option<T> where T: ToJson {
    fn to_json(&self) -> String {
        match self {
            Some(val) => val.to_json(),
            None => String::from("null"),
        }
    }
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for Option where T: ToJson {
    fn to_json(&self) -> String {
        match self {
            Some(val) => val.to_json(),
            None => String::from("null"),
        }
    }
}

The JSON encoder

Ограничения (trait bounds)

Още малко - за Option!

1 2 3 4 5 6 7 8
impl<T> ToJson for Option<T> where T: ToJson {
    fn to_json(&self) -> String {
        match self {
            Some(val) => val.to_json(),
            None => String::from("null"),
        }
    }
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for Option where T: ToJson {
    fn to_json(&self) -> String {
        match self {
            Some(val) => val.to_json(),
            None => String::from("null"),
        }
    }
}

Забележете, че използваме ограничение T: ToJson, за да работи функцията само върху Option, който съдържа стойност имплементираща ToJson.

The JSON encoder

Ограничения (trait bounds)

1 2
impl<T: ToJson> ToJson for Option<T> {
}

е еквиваленто на

1 2 3 4 5
impl<T> ToJson for Option<T>
where
    T: ToJson,
{
}

The JSON encoder

В JSON има списъци, нека да пробваме да го направим за вектор:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
impl<T> ToJson for Vec<T> where T: ToJson {
    fn to_json(&self) -> String {
        let mut iter = self.iter();

        let mut result = match iter.next() {
            Some(first) => first.to_json(),
            None => String::new(),
        };

        for e in iter {
            result.push_str(", ");
            result.push_str(&e.to_json());
        }

        format!("[{}]", result)
    }
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for Option where T: ToJson {
fn to_json(&self) -> String {
match self {
&Some(ref val) => val.to_json(),
&None => String::from("null"),
}
}
}
impl<'a, T> ToJson for &'a T where T: ToJson {
fn to_json(&self) -> String {
(*self).to_json()
}
}
impl ToJson for Vec where T: ToJson {
    fn to_json(&self) -> String {
        let mut iter = self.iter();

        let mut result = match iter.next() {
            Some(first) => first.to_json(),
            None => String::new(),
        };

        for e in iter {
            result.push_str(", ");
            result.push_str(&e.to_json());
        }

        format!("[{}]", result)
    }
}

The JSON encoder

В JSON има списъци, нека да пробваме да го направим за вектор:

1 2 3 4
fn main() {
    let arr = vec![Some(1.1), Some(2.2), None];
    println!("Vector as json: {}", arr.to_json());
}
Vector as json: [1.1, 2.2, null]
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for f32 {
fn to_json(&self) -> String {
format!("{}", self)
}
}
impl ToJson for Option where T: ToJson {
fn to_json(&self) -> String {
match self {
&Some(ref val) => val.to_json(),
&None => String::from("null"),
}
}
}
impl<'a, T> ToJson for &'a T where T: ToJson {
fn to_json(&self) -> String {
(*self).to_json()
}
}
impl  ToJson for Vec where T: ToJson {
fn to_json(&self) -> String {
let mut iter = self.iter();
let first = iter.next();
let mut result = match first {
Some(first) => first.to_json(),
None => String::new(),
};
for e in iter {
result.push_str(", ");
result.push_str(&e.to_json());
}
format!("[{}]", result)
}
}
fn main() {
    let arr = vec![Some(1.1), Some(2.2), None];
    println!("Vector as json: {}", arr.to_json());
}

The JSON encoder

Друг вариант

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
impl<T> ToJson for Vec<T> where T: ToJson {
    fn to_json(&self) -> String {
        match self.as_slice() {
            [] => format!("[]"),
            [first, rest @ ..] => {
                let mut result = first.to_json();

                for e in rest {
                    result.push_str(", ");
                    result.push_str(&e.to_json());
                }

                format!("[{}]", result)
            }
        }
    }
}

fn main() {
    let arr = vec![Some(1.1), Some(2.2), None];
    println!("Vector as json: {}", arr.to_json());
}
Vector as json: [1.1, 2.2, null]
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for Option where T: ToJson {
fn to_json(&self) -> String {
match self {
&Some(ref val) => val.to_json(),
&None => String::from("null"),
}
}
}
impl<'a, T> ToJson for &'a T where T: ToJson {
fn to_json(&self) -> String {
(*self).to_json()
}
}
impl ToJson for f32 {
fn to_json(&self) -> String {
format!("{}", self)
}
}
impl ToJson for Vec where T: ToJson {
    fn to_json(&self) -> String {
        match self.as_slice() {
            [] => format!("[]"),
            [first, rest @ ..] => {
                let mut result = first.to_json();

                for e in rest {
                    result.push_str(", ");
                    result.push_str(&e.to_json());
                }

                format!("[{}]", result)
            }
        }
    }
}

fn main() {
    let arr = vec![Some(1.1), Some(2.2), None];
    println!("Vector as json: {}", arr.to_json());
}

The JSON encoder

А сега и за наш си тип:

1 2 3 4 5 6
struct Student {
    age: i32,
    full_name: String,
    number: i32,
    hobby: Option<String>
}
fn main() {}
struct Student {
    age: i32,
    full_name: String,
    number: i32,
    hobby: Option
}

The JSON encoder

1 2 3 4 5 6 7 8 9 10 11 12 13 14
impl ToJson for Student {
    fn to_json(&self) -> String {
        format!(
r#"{{
    "age": {},
    "full_name": {},
    "number": {},
    "hobby": {}
}}"#,
            self.age.to_json(), self.full_name.to_json(),
            self.number.to_json(), self.hobby.to_json()
        )
    }
}
trait ToJson { fn to_json(&self) -> String; }
struct Student {
age: i32,
full_name: String,
number: i32,
hobby: Option
}
impl ToJson for i32 {
fn to_json(&self) -> String {
format!("{}", self)
}
}
impl ToJson for Option where T: ToJson {
fn to_json(&self) -> String {
match self {
&Some(ref val) => val.to_json(),
&None => String::from("null"),
}
}
}
impl ToJson for String {
fn to_json(&self) -> String {
format!("\"{}\"", self)
}
}
fn main() {}
impl ToJson for Student {
    fn to_json(&self) -> String {
        format!(
r#"{{
    "age": {},
    "full_name": {},
    "number": {},
    "hobby": {}
}}"#,
            self.age.to_json(), self.full_name.to_json(),
            self.number.to_json(), self.hobby.to_json()
        )
    }
}

Упражнение

The JSON encoder

1 2 3 4 5 6 7 8 9 10
fn main() {
    let student = Student {
        age: 16,
        full_name: "Jane Doe".to_owned(),
        number: 5,
        hobby: Some("Tennis".to_string())
    };

    println!("{}", student.to_json());
}
{ "age": 16, "full_name": "Jane Doe", "number": 5, "hobby": "Tennis" }
trait ToJson { fn to_json(&self) -> String; }
struct Student {
age: i32,
full_name: String,
number: i32,
hobby: Option
}
impl ToJson for i32 {
fn to_json(&self) -> String {
format!("{}", self)
}
}
impl ToJson for Option where T: ToJson {
fn to_json(&self) -> String {
match self {
&Some(ref val) => val.to_json(),
&None => String::from("null"),
}
}
}
impl ToJson for String {
fn to_json(&self) -> String {
format!("\"{}\"", self)
}
}
impl ToJson for Student {
fn to_json(&self) -> String {
format!(
r#"{{
"age": {},
"full_name": {},
"number": {},
"hobby": {}
}}"#,
self.age.to_json(), self.full_name.to_json(),
self.number.to_json(), self.hobby.to_json()
)
}
}
fn main() {
    let student = Student {
        age: 16,
        full_name: "Jane Doe".to_owned(),
        number: 5,
        hobby: Some("Tennis".to_string())
    };

    println!("{}", student.to_json());
}

Упражнение

The JSON encoder

Сега можем да си дефинираме функцията, от която започна всичко:

1 2 3
fn to_json<T: ToJson>(value: T) -> String {
    value.to_json()
}
trait ToJson { fn to_json(&self) -> String; }
fn main() {}
fn to_json(value: T) -> String {
    value.to_json()
}

Traits

множество типажи

А ако искаме даден параметър да имплементира повече от един типаж?

1 2 3 4 5 6
fn log_json_transformation<T>(value: T)
where
    T: ToJson + Debug,
{
    println!("{:?} -> {}", value, value.to_json());
}
use std::fmt::Debug;
trait ToJson { fn to_json(&self) -> String; }
fn main() {}
fn log_json_transformation(value: T)
where
    T: ToJson + Debug,
{
    println!("{:?} -> {}", value, value.to_json());
}

Traits

множество типажи

1 2 3 4 5
fn log_json_transformation<T>(value: T)
where
    T: ToJson + Debug,
{
}
use std::fmt::Debug;
trait ToJson { fn to_json(&self) -> String; }
fn main() {}
fn log_json_transformation(value: T)
where
    T: ToJson + Debug,
{
}

е еквивалентно на

1 2 3 4 5 6
fn log_json_transformation<T>(value: T)
where
    T: ToJson,
    T: Debug,
{
}
use std::fmt::Debug;
trait ToJson { fn to_json(&self) -> String; }
fn main() {}
fn log_json_transformation(value: T)
where
    T: ToJson,
    T: Debug,
{
}

Типажи

Предоставени функции

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14
trait Iterator {
    type Item;

    // Задължителен метод.
    // Всеки тип, който имплементира Iterator трябва да придостави имплементация на този метод
    fn next(&mut self) -> Option<Self::Item>;

    // Предоставен метод.
    // Има имплементация по подразбиране, но по избор имплементиращия тип
    // може да предостави своя имплементация.
    fn count(self) -> usize {
        self.fold(0, |acc, _| acc + 1)
    }
}

Типажи

Предоставени функции

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
struct MyVecIter {
    vec: Vec<String>,
    index: usize,
}

impl Iterator for MyVecIter {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index == self.vec.len() {
            return None;
        }

        let elem = self.vec[self.index].clone();
        self.index += 1;
        Some(elem)
    }

    // Използва предоставената имплементация на `count`
    // Сложност: O(n)
}
fn main() {}
struct MyVecIter {
    vec: Vec,
    index: usize,
}

impl Iterator for MyVecIter {
    type Item = String;

    fn next(&mut self) -> Option {
        if self.index == self.vec.len() {
            return None;
        }

        let elem = self.vec[self.index].clone();
        self.index += 1;
        Some(elem)
    }

    // Използва предоставената имплементация на `count`
    // Сложност: O(n)
}

Типажи

Предоставени функции

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
struct MyVecIter {
    vec: Vec<String>,
    index: usize,
}

impl Iterator for MyVecIter {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index == self.vec.len() {
            return None;
        }

        let elem = self.vec[self.index].clone();
        self.index += 1;
        Some(elem)
    }

    // Използва собствена имплементация
    // Сложност: O(1)
    fn count(self) -> usize {
        self.vec.len() - self.index
    }
}
fn main() {}
struct MyVecIter {
    vec: Vec,
    index: usize,
}

impl Iterator for MyVecIter {
    type Item = String;

    fn next(&mut self) -> Option {
        if self.index == self.vec.len() {
            return None;
        }

        let elem = self.vec[self.index].clone();
        self.index += 1;
        Some(elem)
    }

    // Използва собствена имплементация
    // Сложност: O(1)
    fn count(self) -> usize {
        self.vec.len() - self.index
    }
}

Traits

Кога можем да имлементираме типаж?

Traits

Кога можем да имлементираме типаж?

Orphan rule: можем да кажем impl S for T ако:

Traits

static dispatch

Traits

static dispatch

1 2 3
fn to_json<T: ToJson>(value: T) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: T) -> String {
    value.to_json()
}

Traits

static dispatch

1 2 3
fn to_json<T: ToJson>(value: T) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: T) -> String {
    value.to_json()
}

Traits

static dispatch

1 2 3
fn to_json<T: ToJson>(value: T) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: T) -> String {
    value.to_json()
}

Traits

static dispatch

1 2 3
fn to_json<T: ToJson>(value: T) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: T) -> String {
    value.to_json()
}

Traits

static dispatch

1 2 3
fn to_json<T: ToJson>(value: T) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: T) -> String {
    value.to_json()
}

Turbofish!

Trait Objects

dynamic dispatch

1 2 3
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}

Trait Objects

dynamic dispatch

1 2 3
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}

Trait Objects

dynamic dispatch

1 2 3
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}

Trait Objects

dynamic dispatch

1 2 3
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}
fn main() {}
trait ToJson { fn to_json(&self) -> String; }
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}

Trait Objects

dynamic dispatch

Trait Objects

dynamic dispatch

Trait Objects

dynamic dispatch

Trait Objects

dynamic dispatch

Trait Objects

dynamic dispatch

Trait Objects

dynamic dispatch

1 2
println!("{}", mem::size_of::<&u32>());
println!("{}", mem::size_of::<&dyn Debug>());
8 16
use std::fmt::Debug;
use std::mem;
fn main() {
println!("{}", mem::size_of::<&u32>());
println!("{}", mem::size_of::<&dyn Debug>());
}

Trait Objects

dynamic dispatch

1 2 3 4 5 6 7 8 9 10 11
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}

fn main() {
    let trait_object: &dyn ToJson = &5;

    println!("{}", to_json(trait_object));
    println!("{}", to_json(&5));
    println!("{}", to_json(&5 as &dyn ToJson));
}
5 5 5
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for i32 {
fn to_json(&self) -> String {
format!("{}", self)
}
}
fn to_json(value: &dyn ToJson) -> String {
    value.to_json()
}

fn main() {
    let trait_object: &dyn ToJson = &5;

    println!("{}", to_json(trait_object));
    println!("{}", to_json(&5));
    println!("{}", to_json(&5 as &dyn ToJson));
}

Trait Objects

Можем да използваме trait objects да си направим не-хомогенен вектор.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
impl ToJson for Box<dyn ToJson> {
    fn to_json(&self) -> String {
        (**self).to_json()
    }
}

fn main() {
    let values = vec![
        Box::new(1.1_f32) as Box<dyn ToJson>,
        Box::new(3_i32),
        Box::new(String::from("Stuff")),
    ];

    println!("{}", to_json(&values));
}
[1.1, 3, "Stuff"]
trait ToJson { fn to_json(&self) -> String; }
impl ToJson for i32 { fn to_json(&self) -> String { format!("{}", self) } }
impl ToJson for f32 { fn to_json(&self) -> String { format!("{}", self) } }
impl ToJson for String { fn to_json(&self) -> String { format!("{:?}", self) } }
impl  ToJson for Vec where T: ToJson {
fn to_json(&self) -> String {
let mut iter = self.iter();
let first = iter.next();
let mut result = match first {
Some(first) => first.to_json(),
None => String::new(),
};
for e in iter {
result.push_str(", ");
result.push_str(&e.to_json());
}
format!("[{}]", result)
}
}
fn to_json(value: &dyn ToJson) -> String { value.to_json() }
impl ToJson for Box {
    fn to_json(&self) -> String {
        (**self).to_json()
    }
}

fn main() {
    let values = vec![
        Box::new(1.1_f32) as Box,
        Box::new(3_i32),
        Box::new(String::from("Stuff")),
    ];

    println!("{}", to_json(&values));
}

Trait Objects

dyn compatible

Trait Objects

dyn compatible

Trait Objects

dyn compatible

Примери за неща, които правят построяването на виртуална таблица невъзможно

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
trait NotObjectSafe {
    type Item;

    // generic функции
    fn generic<T>(&self, val: &T);

    // функции, които приемат или връщат Self по стойност
    fn receiver_by_value(self);
    fn self_argument(&self, other: Self);
    fn duplicate(&self) -> Self;

    // функции, които приемат или връщат асоцииран тип
    fn get_item(&self) -> &Self::Item;
    fn set_item(&mut self, item: &Self::Item);

    // и други
}
fn main() {}
trait NotObjectSafe {
    type Item;

    // generic функции
    fn generic(&self, val: &T);

    // функции, които приемат или връщат Self по стойност
    fn receiver_by_value(self);
    fn self_argument(&self, other: Self);
    fn duplicate(&self) -> Self;

    // функции, които приемат или връщат асоцииран тип
    fn get_item(&self) -> &Self::Item;
    fn set_item(&mut self, item: &Self::Item);

    // и други
}

Полиморфизъм

1 2 3 4 5 6 7
struct JsonBuilder { /* ... */ }

impl JsonBuilder {
    fn push_key_value(&mut self, key: &str, val: ??) {
        todo!()
    }
}

Полиморфизъм

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
enum JsonValue {
    Null,
    Number(f64),
    String(String),
    List(Vec<JsonValue>),
    Object(HashMap<String, JsonValue>),
}

struct JsonBuilder { /* ... */ }

impl JsonBuilder {
    fn push_key_value(&mut self, key: &str, val: JsonValue) {
        todo!()
    }
}

Полиморфизъм

1 2 3 4 5 6 7 8 9 10 11
trait JsonSerialize {
    /* ... */
}

struct JsonBuilder { /* ... */ }

impl JsonBuilder {
    fn push_key_value<V: JsonSerialize>(&mut self, key: &str, val: &V) {
        todo!()
    }
}

Полиморфизъм

1 2 3 4 5 6 7 8 9 10 11
trait JsonSerialize {
    /* ... */
}

struct JsonBuilder { /* ... */ }

impl JsonBuilder {
    fn push_key_value(&mut self, key: &str, val: &dyn JsonSerialize) {
        todo!()
    }
}

Въпроси