Trait chính là tên gọi khác của interface trong các ngôn ngữ khác như Java, C#…
Trait cho phép chúng ta định nghĩa tên các phương thức nhưng không có phần thân phương thức, mục đích để làm phương thức mẫu cho các struct, rồi các struct có thể code lại (hay implement như trong các ngôn ngữ khác) trait này, tức là có thể code lại phương thức đó tùy theo từng struct, qua đó chúng ta có thể định các phương thức trùng tên cho nhiều struct khác nhau nhưng có ý nghĩa tương đồng với nhau.
Để định nghĩa một trait thì chúng ta dùng cú pháp như sau
trait <tên_trait> {
fn <tên_phương_thức_1>();
fn <tên_phương_thức_2>();
...
}
Lưu ý chúng ta không để cặp dấu ngoặc nhọn {}
sau tên phương thức mà để một dấu chấm phẩy ;
Để code một trait cho một struct thì chúng ta dùng cú pháp như sau:
impl <tên_trait> for <tên_struct> {
fn <tên_phương_thức_1>();
fn <tên_phương_thức_2>();
...
}
Ví dụ:
trait Web {
fn publish(&self);
}
struct Blog {}
impl Web for Blog {
fn publish(&self) {
println!("Publishing new post on blog");
}
}
struct Forum {}
impl Web for Forum {
fn publish(&self) {
println!("Publishing new post on forum");
}
}
fn main() {
let newBlog = Blog{};
let newForum = Forum{};
newBlog.publish();
newForum.publish();
}
Trong đoạn code trên chúng ta định một trait có tên là Web
, bên trong có chứa tên một phương thức có tên là publish()
nhưng không có phần thân hàm mà chỉ có dấu chấm phẩy ở phía sau. Sau đó chúng ta định nghĩa struct Blog
và Forum
(chưa có gì bên trong), rồi viết phần implement
cho các struct này. Ở phần main()
thì chúng ta chỉ đơn giản là gọi các câu lệnh println!()
thôi.
Khi tạo các đối tượng struct này và gọi phương thức publish()
thì tùy đối tượng thuộc struct nào mà phương thức publish()
của struct đó sẽ được gọi.
Publishing new post on blog Publishing new post on forum
Phương thức mặc định
Chúng ta có thể code phương thức mặc định cho trait, khi đó nếu struct nào implement trait mà không code lại phương thức của trait thì đoạn code mặc định của trait đó sẽ được gọi, ví dụ:
trait Web {
fn publish(&self);
fn deletePost(&self) {
println!("Deleting post on this Web");
}
}
struct Blog {}
impl Web for Blog {
fn publish(&self) {
println!("Publishing new post on blog");
}
fn deletePost(&self) {
println!("Deleting post on this Blog");
}
}
struct Forum {}
impl Web for Forum {
fn publish(&self) {
println!("Publishing new post on forum");
}
}
fn main() {
let newBlog = Blog{};
let newForum = Forum{};
newBlog.deletePost();
newForum.deletePost();
}
Trong đoạn code trên chúng ta dùng lại đoạn code ở đầu bài, ở đây chúng ta định nghĩa thêm phương thức deletePost()
cho trait, và có cả phần định nghĩa code bên trong trait luôn, và chúng ta chỉ implement lại phương thức này cho struct Blog
, còn Forum
thì không. Do đó khi gọi phương thức deletePost()
thì phương thức của struct Blog
sẽ được gọi, còn đối với Forum
thì phương thức mặc định của trait sẽ được gọi.
Deleting post on this Blog Deleting post on this Web
Một số đặc điểm:
- Một struct có thể implement bao nhiêu trait cũng được
- Và một trait có thể được implement bởi bao nhiêu struct cũng được
- Trait có thể được implement trên bất kì kiểu dữ liệu nào chứ không chỉ riêng struct