diff --git a/src/ch17-02-trait-objects.md b/src/ch17-02-trait-objects.md
index 6f947b2..edc481f 100644
--- a/src/ch17-02-trait-objects.md
+++ b/src/ch17-02-trait-objects.md
@@ -258,28 +258,16 @@ objects. Clone is an example of one. You'll get errors that will let you know
if a trait can't be a trait object, look up object safety if you're interested
in the details"? Thanks! /Carol -->
-Not all traits can be made into trait objects; only *object safe* traits can. A
-trait is object safe as long as both of the following are true:
+不是所有的trait都可以被放进trait对象中; 只有*对象安全的*trait才可以这样做. 一个trait只有同时满足如下两点时才被认为是对象安全的:
-* The trait does not require `Self` to be `Sized`
-* All of the trait's methods are object safe.
+* 该trait要求`Self`不是`Sized`;
+* 该trait的所有方法都是对象安全的;
-`Self` is a keyword that is an alias for the type that we're implementing
-traits or methods on. `Sized` is a marker trait like the `Send` and `Sync`
-traits that we talked about in Chapter 16. `Sized` is automatically implemented
-on types that have a known size at compile time, such as `i32` and references.
-Types that do not have a known size include slices (`[T]`) and trait objects.
+`Self`是一个类型的别名关键字,它表示当前正被实现的trait类型或者是方法所属的类型. `Sized`是一个像在第16章中介绍的`Send`和`Sync`那样的标记trait, 在编译时它会自动被放进大小确定的类型里,比如`i32`和引用. 大小不确定的类型有切片(`[T]`)和trait对象.
-`Sized` is an implicit trait bound on all generic type parameters by default.
-Most useful operations in Rust require a type to be `Sized`, so making `Sized`
-a default requirement on trait bounds means we don't have to write `T: Sized`
-with most every use of generics. If we want to be able to use a trait on
-slices, however, we need to opt out of the `Sized` trait bound, and we can do
-that by specifying `T: ?Sized` as a trait bound.
+`Sized`是一个默认会被绑定到所有常规类型参数的内隐trait. Rust中要求一个类型是`Sized`的最具可用性的用法是让`Sized`成为一个默认的trait绑定,这样我们就可以在大多数的常规的用法中不去写`T: Sized`了. 如果我们想在切片(slice)中使用一个trait, 我们需要取消对`Sized`的trait绑定, 我们只需制定`T: ?Sized`作为trait绑定.
-Traits have a default bound of `Self: ?Sized`, which means that they can be
-implemented on types that may or may not be `Sized`. If we create a trait `Foo`
-that opts out of the `Self: ?Sized` bound, that would look like the following:
+默认绑定到`Self: ?Sized`的trait可以被实现到是`Sized`或非`Sized`的类型上. 如果我们创建一个不绑定`Self: ?Sized`的trait`Foo`,它看上去应该像这样:
```rust
trait Foo: Sized {
@@ -287,40 +275,21 @@ trait Foo: Sized {
}
```
-The trait `Sized` is now a *super trait* of trait `Foo`, which means trait
-`Foo` requires types that implement `Foo` (that is, `Self`) to be `Sized`.
-We're going to talk about super traits in more detail in Chapter 19.
-
-The reason a trait like `Foo` that requires `Self` to be `Sized` is not allowed
-to be a trait object is that it would be impossible to implement the trait
-`Foo` for the trait object `Foo`: trait objects aren't sized, but `Foo`
-requires `Self` to be `Sized`. A type can't be both sized and unsized at the
-same time!
-
-For the second object safety requirement that says all of a trait's methods
-must be object safe, a method is object safe if either:
-
-* It requires `Self` to be `Sized` or
-* It meets all three of the following:
- * It must not have any generic type parameters
- * Its first argument must be of type `Self` or a type that dereferences to
- the Self type (that is, it must be a method rather than an associated
- function and have `self`, `&self`, or `&mut self` as the first argument)
- * It must not use `Self` anywhere else in the signature except for the
- first argument
-
-Those rules are a bit formal, but think of it this way: if your method requires
-the concrete `Self` type somewhere in its signature, but an object forgets the
-exact type that it is, there's no way that the method can use the original
-concrete type that it's forgotten. Same with generic type parameters that are
-filled in with concrete type parameters when the trait is used: the concrete
-types become part of the type that implements the trait. When the type is
-erased by the use of a trait object, there's no way to know what types to fill
-in the generic type parameters with.
-
-An example of a trait whose methods are not object safe is the standard
-library's `Clone` trait. The signature for the `clone` method in the `Clone`
-trait looks like this:
+Trait`Sized`现在就是trait`Foo`的一个*超级trait*, 也就是说trait`Foo`需要实现了`Foo`的类型(即`Self`)是`Sized`. 我们将在第19章中更详细的介绍超trait(supertrait).
+
+像`Foo`那样要求`Self`是`Sized`的trait不允许成为trait对象的原因是不可能为trait对象`Foo`实现trait`Foo`: trait对象是无确定大小的,但是`Foo`要求`Self`是`Sized`. 一个类型不可能同时既是有大小的又是无确定大小的.
+
+第二点说对象安全要求一个trait的所有方法必须是对象安全的. 一个对象安全的方法满足下列条件:
+
+* 它要求`Self`是`Sized`或者
+* 它符合下面全部三点:
+ * 它不包含任意类型的常规参数
+ * 它的第一个参数必须是类型`Self`或一个引用到`Self`的类型(也就是说它必须是一个方法而非关联函数并且以`self`、`&self`或`&mut self`作为第一个参数)
+ * 除了第一个参数外它不能在其它地方用`Self`作为方法的参数签名
+
+虽然这些规则有一点形式化, 但是换个角度想一下: 如果你的方法在它的参数签名的其它地方也需要具体的`Self`类型参数, 但是一个对象又忘记了它的具体类型是什么, 这时该方法就无法使用被它忘记的原先的具体类型. 当该trait被使用时, 被具体类型参数填充的常规类型参数也是如此: 这个具体的类型就成了实现该trait的类型的某一部分, 如果使用一个trait对象时这个类型被抹掉了, 就没有办法知道该用什么类型来填充这个常规类型参数.
+
+一个trait的方法不是对象安全的一个例子是标准库中的`Clone`trait. `Clone`trait的`clone`方法的参数签名是这样的:
```rust
pub trait Clone {
@@ -328,21 +297,11 @@ pub trait Clone {
}
```
-`String` implements the `Clone` trait, and when we call the `clone` method on
-an instance of `String` we get back an instance of `String`. Similarly, if we
-call `clone` on an instance of `Vec`, we get back an instance of `Vec`. The
-signature of `clone` needs to know what type will stand in for `Self`, since
-that's the return type.
+`String`实现了`Clone` trait, 当我们在一个`String实例上调用`clone`方法时, 我们会得到一个`String`实例. 同样地, 如果我们在一个`Vec`实例上调用`clone`方法, 我们会得到一个`Vec`实例. `clone`的参数签名需要知道`Self`是什么类型, 因为它需要返回这个类型.
-If we try to implement `Clone` on a trait like the `Draw` trait from Listing
-17-3, we wouldn't know whether `Self` would end up being a `Button`, a
-`SelectBox`, or some other type that will implement the `Draw` trait in the
-future.
+如果我们想在像17-3中列出的`Draw`trait那样的trait上实现`Clone`, 我们就不知道`Self`将会是一个`Button`, 一个`SelectBox`, 或者是其它的在将来要实现`Draw`trait的类型.
-The compiler will tell you if you're trying to do something that violates the
-rules of object safety in regards to trait objects. For example, if we had
-tried to implement the `Screen` struct in Listing 17-4 to hold types that
-implement the `Clone` trait instead of the `Draw` trait, like this:
+如果你做了违反trait对象的对象安全性规则的事情, 编译器将会告诉你. 比如, 如果你实现在17-4中列出的`Screen`结构, 你想让该结构像这样持有实现了`Clone`trait的类型而不是`Draw`trait:
```rust,ignore
pub struct Screen {
@@ -350,7 +309,7 @@ pub struct Screen {
}
```
-We'll get this error:
+我们将会得到下面的错误:
```text
error[E0038]: the trait `std::clone::Clone` cannot be made into an object
diff --git a/src/ch17-03-oo-design-patterns.md b/src/ch17-03-oo-design-patterns.md
new file mode 100644
index 0000000..5e65df5
--- /dev/null
+++ b/src/ch17-03-oo-design-patterns.md
@@ -0,0 +1,693 @@
+## 面向对象设计模式的实现
+
+让我们看一下状态设计模式和怎样在Rust中来使用它的例子. *状态模式*就是当一个值有多个内部状态时,值的行为改变基于内部状态. Let's look at an example of the state design pattern and how to use it in Rust.
+The *state pattern* is when a value has some internal state, and the value's
+behavior changes based on the internal state. The internal state is represented
+by a set of objects that inherit shared functionality (we'll use structs and
+traits since Rust doesn't have objects and inheritance). Each state object is
+responsible for its own behavior and the rules for when it should change into
+another state. The value that holds one of these state objects doesn't know
+anything about the different behavior of the states or when to transition
+between states. In the future when requirements change, we won't need to change
+the code of the value holding the state or the code that uses the value. We'll
+only need to update the code inside one of the state objects to change its
+rules, or perhaps add more state objects.
+
+In order to explore this idea, we're going to implement a blog post workflow in
+an incremental way. The workflow that we want our blog posts to follow, once
+we're done with the implementation, is:
+
+1. A blog post starts as an empty draft.
+2. Once the draft is done, we request a review of the post.
+3. Once the post is approved, it gets published.
+4. Only published blog posts return content to print so that we can't
+ accidentally print the text of a post that hasn't been approved.
+
+Any other changes attempted on a post should have no effect. For example, if we
+try to approve a draft blog post before we've requested a review, the post
+should stay an unpublished draft.
+
+Listing 17-11 shows this workflow in code form. This is an example usage of the
+API we're going to implement in a library crate named `blog`:
+
+Filename: src/main.rs
+
+```rust,ignore
+extern crate blog;
+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());
+}
+```
+
+Listing 17-11: Code that demonstrates the desired
+behavior we want our `blog` crate to have
+
+We want to be able to create a new draft blog post with `Post::new`. Then, we
+want to add some text to the blog post while we're in the draft state. If we
+try to print out the post's content immediately, though, we shouldn't get any
+text, since the post is still a draft. We've added an `assert_eq!` here for
+demonstration purposes. Asserting that a draft blog post returns an empty
+string from the `content` method would make an excellent unit test in our
+library, but we're not going to write tests for this example.
+
+Next, we want to be able to request a review of our post, and `content` should
+still return an empty string while waiting for a review. Lastly, when we
+approve the blog post, it should get published, which means the text we added
+will be returned when we call `content`.
+
+Notice that the only type we're interacting with from the crate is the `Post`
+type. The various states a post can be in (draft, waiting for review,
+published) are managed internally to the `Post` type. The states change due to
+the methods we call on the `Post` instance, but we don't have to manage the
+state changes directly. This also means we won't make a mistake with the
+states, like forgetting to request a review before publishing.
+
+### Defining `Post` and Creating a New Instance in the Draft State
+
+Let's get started on the implementation of the library! We know we want to have
+a public `Post` struct that holds some content, so let's start with the
+definition of the struct and an associated public `new` function to create an
+instance of `Post` as shown in Listing 17-12. We're also going to have a
+private trait `State`. `Post` will hold a trait object of `Box` inside
+an `Option` in a private field named `state`. We'll see why the `Option` is
+necessary in a bit. The `State` trait defines all the behavior different post
+states share, and the `Draft`, `PendingReview`, and `Published` states will all
+implement the `State` trait. For now, the trait does not have any methods, and
+we're going to start by defining just the `Draft` state since that's the state
+we want to start in:
+
+Filename: src/lib.rs
+
+```rust
+pub struct Post {
+ state: Option>,
+ content: String,
+}
+
+impl Post {
+ pub fn new() -> Post {
+ Post {
+ state: Some(Box::new(Draft {})),
+ content: String::new(),
+ }
+ }
+}
+
+trait State {}
+
+struct Draft {}
+
+impl State for Draft {}
+```
+
+Listing 17-12: Definition of a `Post` struct and a `new`
+function that creates a new `Post` instance, a `State` trait, and a `Draft`
+struct that implements `State`
+
+When we create a new `Post`, we set its `state` field to a `Some` value holding
+a `Box` pointing to a new instance of the `Draft` struct. This ensures whenever
+we create a new instance of `Post`, it'll start out as a draft. Because the
+`state` field of `Post` is private, there's no way to create a `Post` in any
+other state!
+
+### Storing the Text of the Post Content
+
+In the `Post::new` function, we set the `content` field to a new, empty
+`String`. In Listing 17-11, we showed that we want to be able to call a method
+named `add_text` and pass a `&str` to it to add that text to the content of the
+blog post. We're choosing to implement this as a method rather than exposing
+the `content` field as `pub` because we want to be able to control how the
+`content` field's data is read by implementing a method later. The `add_text`
+method is pretty straightforward though, let's add the implementation in
+Listing 17-13 to the `impl Post` block:
+
+Filename: src/lib.rs
+
+```rust
+# pub struct Post {
+# content: String,
+# }
+#
+impl Post {
+ // ...snip...
+ pub fn add_text(&mut self, text: &str) {
+ self.content.push_str(text);
+ }
+}
+```
+
+Listing 17-13: Implementing the `add_text` method to add
+text to a post's `content`
+
+`add_text` takes a mutable reference to `self`, since we're changing the `Post`
+instance that we're calling `add_text` on. We then call `push_str` on the
+`String` in `content` and pass the `text` argument to add to the saved
+`content`. This isn't part of the state pattern since its behavior doesn't
+depend on the state that the post is in. The `add_text` method doesn't interact
+with the `state` field at all, but it is part of the behavior we want to
+support.
+
+### Content of a Draft Post is Empty
+
+After we've called `add_text` and added some content to our post, we still want
+the `content` method to return an empty string slice since the post is still in
+the draft state, as shown on line 8 of Listing 17-11. For now, let's implement
+the `content` method with the simplest thing that will fulfill this requirement:
+always returning an empty string slice. We're going to change this later once
+we implement the ability to change a post's state to be published. With what we
+have so far, though, posts can only be in the draft state, which means the post
+content should always be empty. Listing 17-14 shows this placeholder
+implementation:
+
+Filename: src/lib.rs
+
+```rust
+# pub struct Post {
+# content: String,
+# }
+#
+impl Post {
+ // ...snip...
+ pub fn content(&self) -> &str {
+ ""
+ }
+}
+```
+
+Listing 17-14: Adding a placeholder implementation for
+the `content` method on `Post` that always returns an empty string slice
+
+With this added `content` method, everything in Listing 17-11 up to line 8
+works as we intend.
+
+### Requesting a Review of the Post Changes its State
+
+Next up is requesting a review of a post, which should change its state from
+`Draft` to `PendingReview`. We want `post` to have a public method named
+`request_review` that will take a mutable reference to `self`. Then we're going
+to call an internal `request_review` method on the state that we're holding, and
+this second `request_review` method will consume the current state and return a
+new state. In order to be able to consume the old state, the second `request_review`
+method needs to take ownership of the state value. This is where the `Option` comes
+in: we're going to `take` the `Some` value out of the `state` field and leave a
+`None` in its place since Rust doesn't let us have unpopulated fields in
+structs. Then we'll set the post's `state` value to the result of this
+operation. Listing 17-15 shows this code:
+
+Filename: src/lib.rs
+
+```rust
+# pub struct Post {
+# state: Option>,
+# content: String,
+# }
+#
+impl Post {
+ // ...snip...
+ pub fn request_review(&mut self) {
+ if let Some(s) = self.state.take() {
+ self.state = Some(s.request_review())
+ }
+ }
+}
+
+trait State {
+ fn request_review(self: Box) -> Box;
+}
+
+struct Draft {}
+
+impl State for Draft {
+ fn request_review(self: Box) -> Box {
+ Box::new(PendingReview {})
+ }
+}
+
+struct PendingReview {}
+
+impl State for PendingReview {
+ fn request_review(self: Box) -> Box {
+ self
+ }
+}
+```
+
+Listing 17-15: Implementing `request_review` methods on
+`Post` and the `State` trait
+
+We've added the `request_review` method to the `State` trait; all types that
+implement the trait will now need to implement the `request_review` method.
+Note that rather than having `self`, `&self`, or `&mut self` as the first
+parameter of the method, we have `self: Box`. This syntax means the
+method is only valid when called on a `Box` holding the type. This syntax takes
+ownership of `Box`, which is what we want because we're transforming the
+old state into a new state, and we want the old state to no longer be valid.
+
+The implementation for the `request_review` method on `Draft` is to return a
+new, boxed instance of the `PendingReview` struct, which is a new type we've
+introduced that represents the state when a post is waiting for a review. The
+`PendingReview` struct also implements the `request_review` method, but it
+doesn't do any transformations. It returns itself since requesting a review on
+a post that's already in the `PendingReview` state should stay in the
+`PendingReview` state.
+
+Now we can start seeing the advantages of the state pattern: the
+`request_review` method on `Post` is the same no matter what its `state` value
+is. Each state is responsible for its own rules.
+
+We're going to leave the `content` method on `Post` as it is, returning an
+empty string slice. We can now have a `Post` in the `PendingReview` state, not
+just the `Draft` state, but we want the same behavior in the `PendingReview`
+state. Listing 17-11 now works up until line 11!
+
+### Approving a Post Changes the Behavior of `content`
+
+The `approve` method on `Post` will be similar to that of the `request_review`
+method: it will set the `state` to the value that the current state says it
+should have when that state is approved. We'll need to add the `approve` method
+to the `State` trait, and we'll add a new struct that implements `State`, the
+`Published` state. Listing 17-16 shows the new code:
+
+Filename: src/lib.rs
+
+```rust
+# pub struct Post {
+# state: Option>,
+# content: String,
+# }
+#
+impl Post {
+ // ...snip...
+ pub fn approve(&mut self) {
+ if let Some(s) = self.state.take() {
+ self.state = Some(s.approve())
+ }
+ }
+}
+
+trait State {
+ fn request_review(self: Box) -> Box;
+ fn approve(self: Box) -> Box;
+}
+
+struct Draft {}
+
+impl State for Draft {
+# fn request_review(self: Box) -> Box {
+# Box::new(PendingReview {})
+# }
+#
+ // ...snip...
+ fn approve(self: Box) -> Box {
+ self
+ }
+}
+
+struct PendingReview {}
+
+impl State for PendingReview {
+# fn request_review(self: Box) -> Box {
+# Box::new(PendingReview {})
+# }
+#
+ // ...snip...
+ fn approve(self: Box) -> Box {
+ Box::new(Published {})
+ }
+}
+
+struct Published {}
+
+impl State for Published {
+ fn request_review(self: Box) -> Box {
+ self
+ }
+
+ fn approve(self: Box) -> Box {
+ self
+ }
+}
+```
+
+Listing 17-16: Implementing the `approve` method on
+`Post` and the `State` trait
+
+Similarly to `request_review`, if we call the `approve` method on a `Draft`, it
+will have no effect since it will return `self`. When we call `approve` on
+`PendingReview`, it returns a new, boxed instance of the `Published` struct.
+The `Published` struct implements the `State` trait, and for both the
+`request_review` method and the `approve` method, it returns itself since the
+post should stay in the `Published` state in those cases.
+
+Now for updating the `content` method on `Post`: we want to return the value in
+the post's `content` field if its state is `Published`, otherwise we want to
+return an empty string slice. Because the goal is to keep all the rules like
+this in the structs that implement `State`, we're going to call a `content`
+method on the value in `state` and pass the post instance (that is, `self`) as
+an argument. Then we'll return the value returned from the `content` method on
+the `state` value as shown in Listing 17-17:
+
+Filename: src/lib.rs
+
+```rust
+# trait State {
+# fn content<'a>(&self, post: &'a Post) -> &'a str;
+# }
+# pub struct Post {
+# state: Option>,
+# content: String,
+# }
+#
+impl Post {
+ // ...snip...
+ pub fn content(&self) -> &str {
+ self.state.as_ref().unwrap().content(&self)
+ }
+ // ...snip...
+}
+```
+
+Listing 17-17: Updating the `content` method on `Post` to
+delegate to a `content` method on `State`
+
+We're calling the `as_ref` method on the `Option` because we want a reference
+to the value inside the `Option`. We're then calling the `unwrap` method, which
+we know will never panic because all the methods on `Post` ensure that the
+`state` value will have a `Some` value in it when those methods are done. This
+is one of the cases we talked about in Chapter 12 where we know that a `None`
+value is never possible even though the compiler isn't able to understand that.
+
+The `content` method on the `State` trait is where the logic for what content
+to return will be. We're going to add a default implementation for the
+`content` method that returns an empty string slice. That lets us not need to
+implement `content` on the `Draft` and `PendingReview` structs. The `Published`
+struct will override the `content` method and will return the value in
+`post.content`, as shown in Listing 17-18:
+
+Filename: src/lib.rs
+
+```rust
+# pub struct Post {
+# content: String
+# }
+trait State {
+ // ...snip...
+ fn content<'a>(&self, post: &'a Post) -> &'a str {
+ ""
+ }
+}
+
+// ...snip...
+struct Published {}
+
+impl State for Published {
+ // ...snip...
+ fn content<'a>(&self, post: &'a Post) -> &'a str {
+ &post.content
+ }
+}
+```
+
+Listing 17-18: Adding the `content` method to the `State`
+trait
+
+Note that we need lifetime annotations on this method, like we discussed in
+Chapter 10. We're taking a reference to a `post` as an argument, and we're
+returning a reference to a part of that `post`, so the lifetime of the returned
+reference is related to the lifetime of the `post` argument.
+
+### Tradeoffs of the State Pattern
+
+We've shown that Rust is capable of implementing the object-oriented state
+pattern in order to encapsulate the different kinds of behavior that a post
+should have that depends on the state that the post is in. The methods on
+`Post` don't know anything about the different kinds of behavior. The way this
+code is organized, we have one place to look in order to find out all the
+different ways that a published post behaves: the implementation of the `State`
+trait on the `Published` struct.
+
+An alternative implementation that didn't use the state pattern might have
+`match` statements in the methods on `Post` or even in the code that uses
+`Post` (`main` in our case) that checks what the state of the post is and
+changes behavior in those places instead. That would mean we'd have a lot of
+places to look in order to understand all the implications of a post being in
+the published state! This would get worse the more states we added: each of
+those `match` statements would need another arm. With the state pattern, the
+`Post` methods and the places we use `Post` don't need `match` statements and
+adding a new state only involves adding a new `struct` and implementing the
+trait methods on that one struct.
+
+This implementation is easy to extend to add more functionality. Here are some
+changes you can try making to the code in this section to see for yourself what
+it's like to maintain code using this pattern over time:
+
+- Only allow adding text content when a post is in the `Draft` state
+- Add a `reject` method that changes the post's state from `PendingReview` back
+ to `Draft`
+- Require two calls to `approve` before changing the state to `Published`
+
+A downside of the state pattern is that since the states implement the
+transitions between the states, some of the states are coupled to each other.
+If we add another state between `PendingReview` and `Published`, such as
+`Scheduled`, we would have to change the code in `PendingReview` to transition
+to `Scheduled` instead. It would be nicer if `PendingReview` wouldn't need to
+change because of the addition of a new state, but that would mean switching to
+another design pattern.
+
+There are a few bits of duplicated logic that are a downside of this
+implementation in Rust. It would be nice if we could make default
+implementations for the `request_review` and `approve` methods on the `State`
+trait that return `self`, but this would violate object safety since the trait
+doesn't know what the concrete `self` will be exactly. We want to be able to
+use `State` as a trait object, so we need its methods to be object safe.
+
+The other duplication that would be nice to get rid of is the similar
+implementations of the `request_review` and `approve` methods on `Post`. They
+both delegate to the implementation of the same method on the value in the
+`Option` in the `state` field, and set the new value of the `state` field to
+the result. If we had a lot of methods on `Post` that followed this pattern, we
+might consider defining a macro to eliminate the repetition (see Appendix E on
+macros).
+
+A downside of implementing this object-oriented pattern exactly as it's defined
+for object-oriented languages is that we're not taking advantage of Rust's
+strengths as much as we could be. Let's take a look at some changes we can make
+to this code that can make invalid states and transitions into compile time
+errors.
+
+#### Encoding States and Behavior as Types
+
+We're going to show how to rethink the state pattern a bit in order to get a
+different set of tradeoffs. Rather than encapsulating the states and
+transitions completely so that outside code has no knowledge of them, we're
+going to encode the states into different types. When the states are types,
+Rust's type checking will make any attempt to use a draft post where we should
+only use published posts into a compiler error.
+
+Let's consider the first part of `main` from Listing 17-11:
+
+Filename: src/main.rs
+
+```rust,ignore
+fn main() {
+ let mut post = Post::new();
+
+ post.add_text("I ate a salad for lunch today");
+ assert_eq!("", post.content());
+}
+```
+
+We still want to create a new post in the draft state using `Post::new`, and we
+still want to be able to add text to the post's content. But instead of having
+a `content` method on a draft post that returns an empty string, we're going to
+make it so that draft posts don't have the `content` method at all. That way,
+if we try to get a draft post's content, we'll get a compiler error that the
+method doesn't exist. This will make it impossible for us to accidentally
+display draft post content in production, since that code won't even compile.
+Listing 17-19 shows the definition of a `Post` struct, a `DraftPost` struct,
+and methods on each:
+
+Filename: src/lib.rs
+
+```rust
+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);
+ }
+}
+```
+
+Listing 17-19: A `Post` with a `content` method and a
+`DraftPost` without a `content` method
+
+Both the `Post` and `DraftPost` structs have a private `content` field that stores the
+blog post text. The structs no longer have the `state` field since we're moving
+the encoding of the state to the types of the structs. `Post` will represent a
+published post, and it has a `content` method that returns the `content`.
+
+We still have a `Post::new` function, but instead of returning an instance of
+`Post`, it returns an instance of `DraftPost`. It's not possible to create an
+instance of `Post` right now since `content` is private and there aren't any
+functions that return `Post`. `DraftPost` has an `add_text` method defined on
+it so that we can add text to `content` as before, but note that `DraftPost`
+does not have a `content` method defined! So we've enforced that all posts
+start as draft posts, and draft posts don't have their content available for
+display. Any attempt to get around these constraints will be a compiler error.
+
+#### Implementing Transitions as Transformations into Different Types
+
+So how do we get a published post then? The rule we want to enforce is that a
+draft post has to be reviewed and approved before it can be published. A post
+in the pending review state should still not display any content. Let's
+implement these constraints by adding another struct, `PendingReviewPost`,
+defining the `request_review` method on `DraftPost` to return a
+`PendingReviewPost`, and defining an `approve` method on `PendingReviewPost` to
+return a `Post` as shown in Listing 17-20:
+
+Filename: src/lib.rs
+
+```rust
+# pub struct Post {
+# content: String,
+# }
+#
+# pub struct DraftPost {
+# content: String,
+# }
+#
+impl DraftPost {
+ // ...snip...
+
+ 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,
+ }
+ }
+}
+```
+
+Listing 17-20: A `PendingReviewPost` that gets created by
+calling `request_review` on `DraftPost`, and an `approve` method that turns a
+`PendingReviewPost` into a published `Post`
+
+The `request_review` and `approve` methods take ownership of `self`, thus
+consuming the `DraftPost` and `PendingReviewPost` instances and transforming
+them into a `PendingReviewPost` and a published `Post`, respectively. This way,
+we won't have any `DraftPost` instances lingering around after we've called
+`request_review` on them, and so forth. `PendingReviewPost` doesn't have a
+`content` method defined on it, so attempting to read its content is a compiler
+error like it is with `DraftPost`. Because the only way to get a published
+`Post` instance that does have a `content` method defined is to call the
+`approve` method on a `PendingReviewPost`, and the only way to get a
+`PendingReviewPost` is to call the `request_review` method on a `DraftPost`,
+we've now encoded the blog post workflow into the type system.
+
+This does mean we have to make some small changes to `main`. Because
+`request_review` and `approve` return new instances rather than modifying the
+struct they're called on, we need to add more `let post = ` shadowing
+assignments to save the returned instances. We also can't have the assertions
+about the draft and pending review post's contents being empty string anymore,
+nor do we need them: we can't compile code that tries to use the content of
+posts in those states any longer. The updated code in `main` is shown in
+Listing 17-21:
+
+Filename: src/main.rs
+
+```rust,ignore
+extern crate blog;
+use blog::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());
+}
+```
+
+Listing 17-21: Modifications to `main` to use the new
+implementation of the blog post workflow
+
+Having to change `main` to reassign `post` is what makes this implementation
+not quite following the object-oriented state pattern anymore: the
+transformations between the states are no longer encapsulated entirely within
+the `Post` implementation. However, we've gained the property of having invalid
+states be impossible because of the type system and type checking that happens
+at compile time! This ensures that certain bugs, such as displaying the content
+of an unpublished post, will be discovered before they make it to production.
+
+Try the tasks suggested that add additional requirements that we mentioned at
+the start of this section to see how working with this version of the code
+feels.
+
+Even though Rust is capable of implementing object-oriented design patterns,
+there are other patterns like encoding state into the type system that are
+available in Rust. These patterns have different tradeoffs than the
+object-oriented patterns do. While you may be very familiar with
+object-oriented patterns, rethinking the problem in order to take advantage of
+Rust's features can give benefits like preventing some bugs at compile-time.
+Object-oriented patterns won't always be the best solution in Rust, since Rust
+has features like ownership that object-oriented languages don't have.
+
+## Summary
+
+No matter whether you think Rust is an object-oriented language or not after
+reading this chapter, you've now seen that trait objects are a way to get some
+object-oriented features in Rust. Dynamic dispatch can give your code some
+flexibility in exchange for a bit of runtime performance. This flexibility can
+be used to implement object-oriented patterns that can help with the
+maintainability of your code. Rust also has different features, like ownership,
+than object-oriented languages. An object-oriented pattern won't always be the
+best way to take advantage of Rust's strengths.
+
+Next, let's look at another feature of Rust that enables lots of flexibility:
+patterns. We've looked at them briefly throughout the book, but haven't seen
+everything they're capable of yet. Let's go!