blob: 13d8cff64074c15d02ac81b8786cb2d7295b8134 [file] [log] [blame] [view] [edit]
## Variables and Mutability
As mentioned in the
[“Storing Values with Variables”][storing-values-with-variables]<!-- ignore -->
section, by default, variables are immutable. This is one of many nudges Rust
gives you to write your code in a way that takes advantage of the safety and
easy concurrency that Rust offers. However, you still have the option to make
your variables mutable. Lets explore how and why Rust encourages you to favor
immutability and why sometimes you might want to opt out.
When a variable is immutable, once a value is bound to a name, you cant change
that value. To illustrate this, generate a new project called _variables_ in
your _projects_ directory by using `cargo new variables`.
Then, in your new _variables_ directory, open _src/main.rs_ and replace its code
with the following code, which wont compile just yet:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/src/main.rs}}
```
Save and run the program using `cargo run`. You should receive an error message
regarding an immutability error, as shown in this output:
```console
{{#include ../listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt}}
```
This example shows how the compiler helps you find errors in your programs.
Compiler errors can be frustrating, but really they only mean your program isnt
safely doing what you want it to do yet; they do _not_ mean that youre not a
good programmer! Experienced Rustaceans still get compiler errors.
You received the error message
`` cannot assign twice to immutable variable `x` `` because you tried to assign
a second value to the immutable `x` variable.
Its important that we get compile-time errors when we attempt to change a value
thats designated as immutable because this very situation can lead to bugs. If
one part of our code operates on the assumption that a value will never change
and another part of our code changes that value, its possible that the first
part of the code wont do what it was designed to do. The cause of this kind of
bug can be difficult to track down after the fact, especially when the second
piece of code changes the value only _sometimes_. The Rust compiler guarantees
that when you state that a value wont change, it really wont change, so you
dont have to keep track of it yourself. Your code is thus easier to reason
through.
But mutability can be very useful, and can make code more convenient to write.
Although variables are immutable by default, you can make them mutable by adding
`mut` in front of the variable name as you did in
[Chapter 2][storing-values-with-variables]<!-- ignore -->. Adding `mut` also
conveys intent to future readers of the code by indicating that other parts of
the code will be changing this variables value.
For example, lets change _src/main.rs_ to the following:
<span class="filename">Filename: src/main.rs</span>
```rust
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-02-adding-mut/src/main.rs}}
```
When we run the program now, we get this:
```console
{{#include ../listings/ch03-common-programming-concepts/no-listing-02-adding-mut/output.txt}}
```
Were allowed to change the value bound to `x` from `5` to `6` when `mut` is
used. Ultimately, deciding whether to use mutability or not is up to you and
depends on what you think is clearest in that particular situation.
### Constants
Like immutable variables, _constants_ are values that are bound to a name and
are not allowed to change, but there are a few differences between constants and
variables.
First, you arent allowed to use `mut` with constants. Constants arent just
immutable by defaulttheyre always immutable. You declare constants using the
`const` keyword instead of the `let` keyword, and the type of the value _must_
be annotated. Well cover types and type annotations in the next section,
[“Data Types”][data-types]<!-- ignore -->, so dont worry about the details
right now. Just know that you must always annotate the type.
Constants can be declared in any scope, including the global scope, which makes
them useful for values that many parts of code need to know about.
The last difference is that constants may be set only to a constant expression,
not the result of a value that could only be computed at runtime.
Heres an example of a constant declaration:
```rust
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
```
The constants name is `THREE_HOURS_IN_SECONDS` and its value is set to the
result of multiplying 60 (the number of seconds in a minute) by 60 (the number
of minutes in an hour) by 3 (the number of hours we want to count in this
program). Rusts naming convention for constants is to use all uppercase with
underscores between words. The compiler is able to evaluate a limited set of
operations at compile time, which lets us choose to write out this value in a
way thats easier to understand and verify, rather than setting this constant to
the value 10,800. See the
[Rust References section on constant evaluation][const-eval] for more
information on what operations can be used when declaring constants.
Constants are valid for the entire time a program runs, within the scope in
which they were declared. This property makes constants useful for values in
your application domain that multiple parts of the program might need to know
about, such as the maximum number of points any player of a game is allowed to
earn, or the speed of light.
Naming hardcoded values used throughout your program as constants is useful in
conveying the meaning of that value to future maintainers of the code. It also
helps to have only one place in your code you would need to change if the
hardcoded value needed to be updated in the future.
### Shadowing
As you saw in the guessing game tutorial in
[Chapter 2][comparing-the-guess-to-the-secret-number]<!-- ignore -->, you can
declare a new variable with the same name as a previous variable. Rustaceans say
that the first variable is _shadowed_ by the second, which means that the second
variable is what the compiler will see when you use the name of the variable. In
effect, the second variable overshadows the first, taking any uses of the
variable name to itself until either it itself is shadowed or the scope ends. We
can shadow a variable by using the same variables name and repeating the use of
the `let` keyword as follows:
<span class="filename">Filename: src/main.rs</span>
```rust
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-03-shadowing/src/main.rs}}
```
This program first binds `x` to a value of `5`. Then it creates a new variable
`x` by repeating `let x =`, taking the original value and adding `1` so the
value of `x` is then `6`. Then, within an inner scope created with the curly
brackets, the third `let` statement also shadows `x` and creates a new variable,
multiplying the previous value by `2` to give `x` a value of `12`. When that
scope is over, the inner shadowing ends and `x` returns to being `6`. When we
run this program, it will output the following:
```console
{{#include ../listings/ch03-common-programming-concepts/no-listing-03-shadowing/output.txt}}
```
Shadowing is different from marking a variable as `mut` because well get a
compile-time error if we accidentally try to reassign to this variable without
using the `let` keyword. By using `let`, we can perform a few transformations on
a value but have the variable be immutable after those transformations have been
completed.
The other difference between `mut` and shadowing is that because were
effectively creating a new variable when we use the `let` keyword again, we can
change the type of the value but reuse the same name. For example, say our
program asks a user to show how many spaces they want between some text by
inputting space characters, and then we want to store that input as a number:
```rust
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-04-shadowing-can-change-types/src/main.rs:here}}
```
The first `spaces` variable is a string type and the second `spaces` variable is
a number type. Shadowing thus spares us from having to come up with different
names, such as `spaces_str` and `spaces_num`; instead, we can reuse the simpler
`spaces` name. However, if we try to use `mut` for this, as shown here, well
get a compile-time error:
```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/src/main.rs:here}}
```
The error says were not allowed to mutate a variables type:
```console
{{#include ../listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt}}
```
Now that weve explored how variables work, lets look at more data types they
can have.
[comparing-the-guess-to-the-secret-number]: ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number
[data-types]: ch03-02-data-types.html#data-types
[storing-values-with-variables]: ch02-00-guessing-game-tutorial.html#storing-values-with-variables
[const-eval]: ../reference/const_eval.html