Безопасность объектов трейта
Безопасность объектов трейта (object safety) - это характеристика трейта,
которая определяет, можно ли использовать этот трейт как тип
для dyn Trait и вызывать его методы через динамическую
диспетчеризацию. Трейт, удовлетворяющий правилам объектной
безопасности, называется объектно-безопасным (object-safe).
Если трейт не является объектно-безопасным, компилятор выдаст
ошибку при попытке создать dyn Trait или
Box<dyn Trait>. Основные правила: методы не должны
возвращать Self по значению, не должны иметь
обобщённых параметров типа, не должны быть статическими,
а также трейт не должен требовать Sized для Self.
Синтаксис
trait TraitName
{
fn method(&self);
}
let value: Box<dyn TraitName>;
Пример
Давайте создадим объектно-безопасный трейт Shape
с методом area и используем его через Box<dyn Shape>:
trait Shape
{
fn area(&self) -> f64;
}
struct Circle
{
radius: f64,
}
impl Shape for Circle
{
fn area(&self) -> f64
{
3.14 * self.radius * self.radius
}
}
fn main()
{
let shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 2.0 }),
];
for shape in &shapes
{
println!("{}", shape.area());
}
}
Результат выполнения кода:
12.56
Пример
Давайте попробуем создать трейт с методом, возвращающим Self,
что нарушает объектную безопасность:
trait Cloneable
{
fn clone_self(&self) -> Self;
}
fn main()
{
let _value: Box<dyn Cloneable>;
}
Результат выполнения кода:
error[E0038]: the trait `Cloneable` cannot be made into an object
Пример
Давайте создадим объектно-безопасный трейт с методом по умолчанию
и используем его через &dyn Trait:
trait Greeter
{
fn name(&self) -> String;
fn greet(&self) -> String
{
format!("Hello, {}!", self.name())
}
}
struct Person
{
name: String,
}
impl Greeter for Person
{
fn name(&self) -> String
{
self.name.clone()
}
}
fn main()
{
let person = Person { name: String::from("abcde") };
let greeter: &dyn Greeter = &person;
println!("{}", greeter.greet());
}
Результат выполнения кода:
"Hello, abcde!"
Смотрите также
-
ключевое слово
dyn,
которое используется для динамической диспетчеризации трейтов -
ключевое слово
trait,
которое объявляет трейт в Rust -
конструкция
trait bound,
которая ограничивает обобщённые типы трейтами -
типаж
Sized,
который влияет на объектную безопасность трейта