面向对象编程特性
隐藏实现细节的封装
对象的实现细节不能被使用该对象的代码访问
- pub关键字来决定我们代码中的哪些模块、类型、函数和方法应该是公共的
- 默认情况下其他所有内容都是私有的
继承作为类型系统和代码共享
- 继承是一种机制,通过它一个对象可以继承另一个对象定义中的元素,从而获得父对象的数据和行为,而无需再次定义它们
- 在不使用宏的情况下,没有办法定义一个继承父结构体的字段和方法实现的结构体
- Rust不具有该特性
多态性
可以处理多种类型数据的代码
- Rust则使用泛型来抽象不同可能的类型,并使用特征边界来强制这些类型必须提供什么。这有时被称为有界参数多态性
- Rust采用了不同的方法,使用特征对象(trait object)而不是继承
Trait Object
为通用行为定义Trait
Trait Object
- Rust提供泛型来支持抽象编程,但泛型要求类型在编译期已知
- Trait对象(Trait Object)是另一种抽象方式:在运行时支持不同类型的值,前提是它们实现了某个trait
- 类似于OOP中的“接口+多态”或“鸭子类型”
例:
main.rs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| use trysomething::{Button, Draw, Screen};
struct SelectBox { width: u32, height: u32, options: Vec<String> }
impl Draw for SelectBox { fn draw(&self) { println!("SelectBox!"); } }
fn main() { let screen = Screen { comonents: vec![ Box::new( SelectBox { width: 75, height: 10, options: vec![ String::from("Yes"), String::from("Maybe"), String::from("No") ] } ), Box::new( Button { width: 50, height: 10, label: String::from("OK") } ) ] };
screen.run(); }
|
lib.rs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| pub trait Draw { fn draw(&self); }
pub struct Screen { pub comonents: Vec<Box<dyn Draw>>, }
impl Screen { pub fn run(&self) { for component in self.comonents.iter() { component.draw(); } } }
pub struct Button { pub width: u32, pub height: u32, pub label: String }
impl Draw for Button { fn draw(&self) { println!("Button!"); } }
|
面向对象的特性
实现一个__的设计模式 – State Patten
是将某对象定义一些值作为该对象的状态?与代码相分离,方便代码修改时不用在同步修改状态定义?
lib.rs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| pub struct Post { state: Option<Box<dyn State>>, content: String }
impl Post { pub fn new() -> Post { Post { state: Some(Box::new(Draft {})), content: String::new() } }
pub fn add_text(&mut self, text: &str) { self.content.push_str(text); }
pub fn content(&self) -> &str { self.state.as_ref().unwrap().content(self) }
pub fn request_review(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.request_review()) } }
pub fn approve(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.approve()) } } }
trait State { fn request_review(self: Box<Self>) -> Box<dyn State>; fn approve(self: Box<Self>) -> Box<dyn State>; fn content<'a>(&self, post: &'a Post) -> &'a str { "" } }
struct Draft {}
impl State for Draft { fn request_review(self: Box<Self>) -> Box<dyn State> { Box::new(PendingReview {}) }
fn approve(self: Box<Self>) -> Box<dyn State> { self } }
struct PendingReview {}
impl State for PendingReview { fn request_review(self: Box<Self>) -> Box<dyn State> { self } fn approve(self: Box<Self>) -> Box<dyn State> { Box::new(Published {}) } }
struct Published {}
impl State for Published { fn request_review(self: Box<Self>) -> Box<dyn State> { self }
fn approve(self: Box<Self>) -> Box<dyn State> { self }
fn content<'a>(&self, post: &'a Post) -> &'a str { &post.content } }
|
main.rs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| use trysomething::Post;
fn main() { let mut post = Post::new();
post.add_text("I ate a salad for lunch today"); assert_eq!("", post.content());
post.request_review(); assert_eq!("", post.content());
post.approve(); assert_eq!("I ate a salad for lunch today", post.content()); }
|
例2:
lib.rs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| pub struct Post { content: String }
pub struct DraftPost { content: String }
impl Post { pub fn new() -> DraftPost { DraftPost { content: String::new() } }
pub fn content(&self) -> &str { &self.content } }
impl DraftPost { pub fn add_text(&mut self, text: &str) { self.content.push_str(text); }
pub fn request_review(self) -> PendingReviewPost { PendingReviewPost { content: self.content } } }
pub struct PendingReviewPost { content: String }
impl PendingReviewPost { pub fn approve(self) -> Post { Post { content: self.content } } }
|
main.rs:
1 2 3 4 5 6 7 8 9 10 11 12 13
| use trysomething::Post;
fn main() { let mut post = Post::new();
post.add_text("I ate a salad for lunch today");
let post = post.request_review(); let post =post.approve();
assert_eq!("I ate a salad for lunch today", post.content()); }
|