Trait的基本用法
Trait最基本的作用是從多種類型中抽取出共性的屬性或方法,並定義這些方法的規範(即方法簽名)。
例如,對於Audio類型和Video類型,它們有幾個具有共性的方法:
- play方法用於播放
- pause方法用於暫停
- get_duration方法用於顯示媒體的總時長
為了抽取這些共性方法,可定義一個名為Playable的Trait,並在其中規範好這些方法的簽名。
自定義Trait類型時,使用trait
關鍵字。如:
#![allow(unused)] fn main() { trait Playable { fn play(&self); fn pause(&self) { println!("pause"); } fn get_duration(&self) -> f32; } }
注意上面的play方法和get_duration方法都僅僅只規範了它們的方法簽名,並沒有為它們定義方法體,而pause方法則指定了函數簽名且定義了方法體,這個方法體是pause方法的默認方法體。
定義好Playable Trait後,先讓Audio類型去實現Playable:
#![allow(unused)] fn main() { struct Audio { name: String, duration: f32, } impl Playable for Audio { fn play(&self) { println!("listening audio: {}", self.name); } fn get_duration(&self) -> f32 { self.duration } } }
注意,上面impl Playable for Audio
表示為Audio類型實現Playable Trait。Audio實現Playable Trait時,Trait中的所有沒有提供默認方法體的方法(即play方法和get_duration方法)都需要實現。對於提供了默認方法體的方法,可實現可不實現,如果實現了則覆蓋默認方法體,如果沒有實現,則使用默認方法體。
下面再為Video類型實現Playable Trait,這裡也實現了有默認方法體的pause方法:
#![allow(unused)] fn main() { struct Video { name: String, duration: f32, } impl Playable for Video { fn play(&self) { println!("watching video: {}", self.name); } fn pause(&self) { println!("video paused"); } fn get_duration(&self) -> f32 { self.duration } } }
當Audio類型和Video類型實現了Playable Trait後,這兩個類型的實例對象自然可以去調用它們各自定義的方法。而對於Audio沒有定義的pause方法,則會從其所實現的Trait中尋找。
fn main() { let audio = Audio{ name: "telephone.mp3".to_string(), duration: 4.32, }; audio.play(); audio.pause(); println!("{}", audio.get_duration()); let video = Video { name: "Yui Hatano.mp4".to_string(), duration: 59.59, }; video.play(); video.pause(); println!("{}", video.get_duration()); }