面向对象语言的特性
对象包含数据和行为 封装实现细节 作为类型系统和代码共享机制的继承 使用trait对象来存储不同类型的值
为共有行为定义一个trait 实现trait trait对象会执行动态派发 trait对象必须保证对象安全 实现一种面向对象的设计模式
定义Post并新建一个处于草稿状态下的新实例 存储文章内容的文本 确保草稿的可读内容为空 请求审批文章并改变其状态 添加approve方法来改变content的行为 状态模式的权衡取舍
OOP
main.rs:
use OOP:: { Screen, Button, SelectBox} ;
fn main ( ) {
let screen = Screen {
components: 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:
pub struct AveragedCollection {
list: Vec< i32> ,
average: f64,
}
impl AveragedCollection {
pub fn add ( & mut self, value: i32) {
self. list. push ( value) ;
self. update_average ( ) ;
}
pub fn remove ( & mut self) -> Option< i32> {
let result = self. list. pop ( ) ;
match result {
Some ( value) = > {
self. update_average ( ) ;
Some ( value)
} ,
None = > None,
}
}
pub fn average ( & self) -> f64 {
self. average
}
fn update_average ( & mut self) {
let total: i32 = self. list. iter ( ) . sum ( ) ;
self. average = total as f64 / self. list. len ( ) as f64;
}
}
pub trait Draw {
fn draw ( & self) ;
}
pub struct Screen {
pub components: Vec< Box< dyn Draw>> ,
}
impl Screen {
pub fn run ( & self) {
for component in self. components. iter ( ) {
component. draw ( ) ;
}
}
}
pub struct Button {
pub width: u32,
pub height: u32,
pub label: String,
}
impl Draw for Button {
fn draw ( & self) {
}
}
pub struct SelectBox {
pub width: u32,
pub height: u32,
pub options: Vec< String> ,
}
impl Draw for SelectBox {
fn draw ( & self) {
}
}
post
main.rs:
use blog:: 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 ( ) ) ;
}
lib.rs:
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
}
}
post_2
main.rs:
use blog_2:: 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 ( ) ) ;
}
lib.rs:
pub struct Post {
content: String,
}
pub struct DraftPost {
content: String,
}
pub struct PendingReviewPost {
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,
}
}
}
impl PendingReviewPost {
pub fn approve ( self) -> Post {
Post {
content: self. content,
}
}
}