Rust позволяет реализовать трейты глобально для набора типов или вообще для всех типов. Это упрощает применение трейтов, поскольку нам не надо прописывать реализацию для каждого типа по отдельности.
Рассмотрим простейший пример:
struct Message { text: String}
struct Person { name: String}
trait Printer{ fn print(&self); }
impl<T> Printer for T{
fn print(&self){
println!("Печать");
}
}
fn main(){
let mes = Message {text: String::from("Hello Rust")};
mes.print();
let tom = Person{name: String::from("Tom")};
tom.print();
}
Здесь у нас для целей демонстрации определены две структуры - Person и Message и трейт Printer с методом print. Далее мы реализуем этот трейт следующим образом:
impl<T> Printer for T{
То есть мы указываем, что трейт реализуется для любого типа T. В реализации метода print просто выводим некоторую строку, которая не зависит от конкретного типа. В итоге мы сможем применить метод print у обоих структур:
let mes = Message {text: String::from("Hello METANIT.COM")};
mes.print();
let tom = Person{name: String::from("Tom")};
tom.print();
Консольный вывод:
Печать Печать
Однако поскольку этот тип T может иметь любую функциональность, то в данном случае мы ограничены в ее использовании. Соответственно мы не можем использовать поля структуры внутри реализации метода print. Но рассмотрим другой пример:
struct Message { text: String}
struct Person { name: String}
trait Printer{ fn print(&self); }
impl Printer for Message{
fn print(&self){
println!("Message text: {}", self.text);
}
}
impl Printer for Person{
fn print(&self){
println!("Person name: {}", self.name);
}
}
trait ConsolePrinter{ fn console_print(&self); }
impl<T:Printer> ConsolePrinter for T{
fn console_print(&self){
println!("******Печать на консоль*****");
self.print();
println!(); // для отделения строк при выводе на консоль
}
}
fn main(){
let mes = Message {text: String::from("Hello METANIT.COM")};
mes.console_print();
let tom = Person{name: String::from("Tom")};
tom.console_print();
}
Здесь трейт Printer по отдельности применяется к обоим структурам. Но также определен трейт Console_Printer, который применяется только к тем типам, которые реализуют трейт Printer:
impl<T:Printer> ConsolePrinter for T{
Благодаря этому нам не надо по отдельности применять этот трейт к обоим структурам. Консольный вывод:
******Печать на консоль***** Message text: Hello METANIT.COM ******Печать на консоль***** Person name: Tom