Компилятору Rust нужно знать сколько места занимает результат каждой функции. Это обозначает, что все ваши функции имеют конкретный тип результата. В отличие от других языком, если у вас есть типаж, например Animal, то вы не можете написать функцию, которая вернёт Animal, по той причине, что разные реализации этого типажа будут занимать разное количество памяти.
Однако есть простой обходной путь. Вместо не посредственного возврата типажа-объекта, наши функции могут возвращать Box, который
Rust пытается быть предельно явным, когда он выделяет память в куче. Так что если ваша функция возвращает указатель-на-типаж-в-куче, вы должны дописать к возвращаемому типу ключевое слово dyn, например Box
struct Sheep {}
struct Cow {}
trait Animal {
// Сигнатура метода объекта
fn noise(&self) -> &'static str;
}
// Реализуем типаж `Animal` для `Sheep`.
impl Animal for Sheep {
fn noise(&self) -> &'static str {
"baaaaah!"
}
}
// Реализуем типаж `Animal` для `Cow`.
impl Animal for Cow {
fn noise(&self) -> &'static str {
"moooooo!"
}
}
// Вернём некоторую структуру, которая реализует `Animal`, но которая не известна в момент компиляции.
fn random_animal(random_number: f64) -> Box
if random_number < 0.5 {
Box::new(Sheep {})
} else {
Box::new(Cow {})
}
}
fn main() {
let random_number = 0.234;
let animal = random_animal(random_number);
println!("Вы выбрали случайное животное и оно говорит {}", animal.noise());
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
В Rust, множество операторов могут быть перегружены с помощью типажей. То есть, некоторые операторы могут использоваться для выполнения различных задач на основе вводимых аргументов. Это возможно, потому что операторы являются синтаксическим сахаром для вызова методов. Например, оператор + в a + b вызывает метод add (как в a.add(b)). Метод add является частью типажа Add. Следовательно, оператор + могут использовать все, кто реализуют типаж Add.
Список типажей, таких как Add, которые перегружают операторы, доступен здесь.
use std::ops;
struct Foo;
struct Bar;
#[derive(Debug)]
struct FooBar;
#[derive(Debug)]
struct BarFoo;
// Типаж `std::ops::Add` используется для указания функциональности `+`.
// Здесь мы объявим `Add
// операндом типа `Bar`.
// Следующий блок реализует операцию: Foo + Bar = FooBar
impl ops::Add
type Output = FooBar;
fn add(self, _rhs: Bar) -> FooBar {
println!("> Вызвали Foo.add(Bar)");
FooBar
}
}
// Если мы поменяем местами типы, то получим реализацию некоммутативного сложения.