Lesson 5.2 · 8 min
Giving a struct behaviour
A Message can hold an author and a text, but everything you do with one still lives in loose functions. An impl block puts the actions next to the data they act on.
Adds to ChatterboxMessage::new, plus shout and is_empty methods.
Functions that live with the struct
You can already write fn describe(msg: &Message). An impl block lets you attach that same function to the type, so it is called with a dot: msg.shout(). Same borrowing rules as chapter 4; just a tidier address.
Two kinds of thing go in an impl. A function without self, like new, is called on the type: Message::new(..). A function whose first parameter is self is a method, called on a value.
$ cargo run
HELLO THERE
false&self is shorthand for "borrow this message, read only". Inside the method, self.text is the field. The caller keeps the key, which is why you can call shout and then is_empty on the same m.
A method that needs to change the message says &mut self, the exclusive borrow from lesson 4.4.
error[E0596]: cannot borrow `m` as mutable, as it is not declared as mutable --> src/main.rs:18:5 | 18 | m.clear(); | ^ cannot borrow as mutable | help: consider changing this to be mutable | 17 | let mut m = Message::new("you", "oops"); | +++
E0596: "cannot borrow m as mutable, as it is not declared as mutable". Calling clear quietly takes a &mut borrow of m, and you never said m could change. The fix is the same word as in lesson 2.2: let mut m.
So the signature is a promise you can read from outside. &self: looks only. &mut self: may change it. self: takes the key and gives it away.
What does this print?
HIHIhiHIHIit does not compile
Reveal the answer
The program prints: HIHIhi shout borrows with &self and returns a brand-new String. The original m.text is untouched and m is still usable, so you can call it as often as you like.
$ cargo run
HELLO trueFill in both methods. word_count only looks and returns how many words are in the text: split_whitespace() splits text into words and .count() counts what it gives you. The count is a usize, a whole number used for sizes and positions. append changes the message: it adds a space and then the extra text to the end.
Fill in both methods. word_count only looks and returns how many words are in the text: split_whitespace() splits text into words and .count() counts what it gives you. The count is a usize, a whole number used for sizes and positions. append changes the message: it adds a space and then the extra text to the end.
Hidden tests (4): append_joins_with_a_space append_then_count counts_words empty_has_no_words
This exercise runs real Rust in your browser through the official Rust Playground, so it needs JavaScript.
Say it out loud, then reveal
What is the difference between <code>Message::new(..)</code> and <code>m.shout()</code>?Reveal
new has no self, so it is called on the type and builds a value. shout takes &self, so it is called with a dot on a value that exists.Why did <code>m.clear()</code> fail with E0596?Reveal
clear needs &mut self, an exclusive borrow, and m was not declared mut.What does <code>&self</code> promise the caller?Reveal
That is lesson 5.2. Tick it off so the course remembers where you are.