Lesson 3.4 · 9 min
Giving code a name
The chat loop is getting crowded: banner text, reply rules and the loop itself all sit in main. A function lets you give a piece of code a name, so main can say what it does instead of how.
Adds to Chatterboxreply() is its own function.
The shape of a function
You have been writing one since lesson 1.1: fn main(). A function is fn, a name, a list of inputs in brackets, an arrow and the type of what comes out, then the body in braces.
Each input is written name: Type, and the type is required: Rust never guesses at a function's edges. That is how a reader, and the compiler, know how to call it without reading the body.
$ cargo run
hello!
bye!Two things to notice. &str is the plain-text type from lesson 2.4, and the String coming out is text the function made itself. And the body's last line, format!("{text}!"), has no semicolon. That is how a function hands back a value: whatever the last line produces is the answer. It is the same rule as the if blocks in lesson 3.1.
The classic slip
Add a semicolon and the last line turns into a statement that produces nothing:
error[E0308]: mismatched types --> src/main.rs:1:25 | 1 | fn shout(text: &str) -> String { | ----- ^^^^^^ expected `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression 2 | format!("{text}!"); | - help: remove this semicolon to return this value
The message says the function was promised to return a String but its body gives (), which is Rust's word for "nothing". The compiler even points at the semicolon and suggests removing it. Remember this one: you will see it again.
What does this print?
Chatterbox v0.3 (once)Chatterbox v0.3 Chatterbox v0.3banner()
Reveal the answer
The program prints: Chatterbox v0.3 Chatterbox v0.3 Every call runs the body again. Writing the code once and calling it from several places is the whole point: change the banner in one spot and every caller gets the change.
Chatterbox v0.3, tidied
The program behaves the same, but main is now short enough to read in one glance. banner() builds the first line, and reply() holds the rules for what to say back. The loop only decides when to stop. Every line that reaches reply() now counts as a message, the commands included, which is a small change we will clean up when messages get a proper shape in chapter 5.
$ cargo run
Chatterbox v0.3
Hi Sam! I'm Chatterbox.
you: hello
(nothing to say)
commands: /help, /quit
you: how are you
bye, Sam!
messages so far: 4Write the body of reply. An empty message returns (nothing to say), /help returns commands: /help, /quit, and anything else returns you: plus the text. Mind the semicolon.
Write the body of reply. An empty message returns (nothing to say), /help returns commands: /help, /quit, and anything else returns you: plus the text. Mind the semicolon.
Hidden tests (3): empty_message echoes_the_rest help_message
This exercise runs real Rust in your browser through the official Rust Playground, so it needs JavaScript.
Say it out loud, then reveal
Why does the last line of a function body have no semicolon?Reveal
What do the parts of fn reply(msg: &str) -> String mean?Reveal
What does E0308 say when a function body ends in a semicolon?Reveal
That is lesson 3.4. Tick it off so the course remembers where you are.
Sources The Rust Book: functions