207 lines
12 KiB
HTML
207 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Variables and Mutability</title>
|
||
</head>
|
||
<body>
|
||
<h2 id="variables-and-mutability"><a class="header" href="#variables-and-mutability">Variables and Mutability</a></h2>
|
||
<p>As mentioned in the <a href="../ch02/ch02-00-guessing-game-tutorial.html#storing-values-with-variables">“Storing Values with
|
||
Variables”</a><!-- 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.
|
||
Let’s explore how and why Rust encourages you to favor immutability and why
|
||
sometimes you might want to opt out.</p>
|
||
<p>When a variable is immutable, once a value is bound to a name, you can’t change
|
||
that value. To illustrate this, generate a new project called <em>variables</em> in
|
||
your <em>projects</em> directory by using <code>cargo new variables</code>.</p>
|
||
<p>Then, in your new <em>variables</em> directory, open <em>src/main.rs</em> and replace its
|
||
code with the following code, which won’t compile just yet:</p>
|
||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||
<pre><code class="language-rust ignore does_not_compile">fn main() {
|
||
let x = 5;
|
||
println!("The value of x is: {x}");
|
||
x = 6;
|
||
println!("The value of x is: {x}");
|
||
}</code></pre>
|
||
<p>Save and run the program using <code>cargo run</code>. You should receive an error message
|
||
regarding an immutability error, as shown in this output:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling variables v0.1.0 (file:///projects/variables)
|
||
error[E0384]: cannot assign twice to immutable variable `x`
|
||
--> src/main.rs:4:5
|
||
|
|
||
2 | let x = 5;
|
||
| - first assignment to `x`
|
||
3 | println!("The value of x is: {x}");
|
||
4 | x = 6;
|
||
| ^^^^^ cannot assign twice to immutable variable
|
||
|
|
||
help: consider making this binding mutable
|
||
|
|
||
2 | let mut x = 5;
|
||
| +++
|
||
|
||
For more information about this error, try `rustc --explain E0384`.
|
||
error: could not compile `variables` (bin "variables") due to 1 previous error
|
||
</code></pre>
|
||
<p>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
|
||
isn’t safely doing what you want it to do yet; they do <em>not</em> mean that you’re
|
||
not a good programmer! Experienced Rustaceans still get compiler errors.</p>
|
||
<p>You received the error message <code>cannot assign twice to immutable variable `x`</code> because you tried to assign a second value to the immutable <code>x</code> variable.</p>
|
||
<p>It’s important that we get compile-time errors when we attempt to change a
|
||
value that’s 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, it’s possible
|
||
that the first part of the code won’t 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 <em>sometimes</em>. The Rust
|
||
compiler guarantees that when you state that a value won’t change, it really
|
||
won’t change, so you don’t have to keep track of it yourself. Your code is thus
|
||
easier to reason through.</p>
|
||
<p>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 <code>mut</code> in front of the variable name as you did in <a href="../ch02/ch02-00-guessing-game-tutorial.html#storing-values-with-variables">Chapter
|
||
2</a><!-- ignore -->. Adding <code>mut</code> also conveys
|
||
intent to future readers of the code by indicating that other parts of the code
|
||
will be changing this variable’s value.</p>
|
||
<p>For example, let’s change <em>src/main.rs</em> to the following:</p>
|
||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||
<pre class="playground"><code class="language-rust edition2024">fn main() {
|
||
let mut x = 5;
|
||
println!("The value of x is: {x}");
|
||
x = 6;
|
||
println!("The value of x is: {x}");
|
||
}</code></pre>
|
||
<p>When we run the program now, we get this:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling variables v0.1.0 (file:///projects/variables)
|
||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30s
|
||
Running `target/debug/variables`
|
||
The value of x is: 5
|
||
The value of x is: 6
|
||
</code></pre>
|
||
<p>We’re allowed to change the value bound to <code>x</code> from <code>5</code> to <code>6</code> when <code>mut</code> 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.</p>
|
||
<!-- Old headings. Do not remove or links may break. -->
|
||
<p><a id="constants"></a></p>
|
||
<h3 id="declaring-constants"><a class="header" href="#declaring-constants">Declaring Constants</a></h3>
|
||
<p>Like immutable variables, <em>constants</em> are values that are bound to a name and
|
||
are not allowed to change, but there are a few differences between constants
|
||
and variables.</p>
|
||
<p>First, you aren’t allowed to use <code>mut</code> with constants. Constants aren’t just
|
||
immutable by default—they’re always immutable. You declare constants using the
|
||
<code>const</code> keyword instead of the <code>let</code> keyword, and the type of the value <em>must</em>
|
||
be annotated. We’ll cover types and type annotations in the next section,
|
||
<a href="ch03-02-data-types.html#data-types">“Data Types”</a><!-- ignore -->, so don’t worry about the details
|
||
right now. Just know that you must always annotate the type.</p>
|
||
<p>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.</p>
|
||
<p>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.</p>
|
||
<p>Here’s an example of a constant declaration:</p>
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
|
||
<span class="boring">}</span></code></pre>
|
||
<p>The constant’s name is <code>THREE_HOURS_IN_SECONDS</code>, 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). Rust’s 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 that’s easier to understand and verify, rather than setting this constant
|
||
to the value 10,800. See the <a href="../reference/const_eval.html">Rust Reference’s section on constant
|
||
evaluation</a> for more information on what operations can be used
|
||
when declaring constants.</p>
|
||
<p>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.</p>
|
||
<p>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 that you would need to change if the
|
||
hardcoded value needed to be updated in the future.</p>
|
||
<h3 id="shadowing"><a class="header" href="#shadowing">Shadowing</a></h3>
|
||
<p>As you saw in the guessing game tutorial in <a href="../ch02/ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number">Chapter
|
||
2</a><!-- ignore -->, you can declare a
|
||
new variable with the same name as a previous variable. Rustaceans say that the
|
||
first variable is <em>shadowed</em> 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 variable’s name and repeating the
|
||
use of the <code>let</code> keyword as follows:</p>
|
||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||
<pre class="playground"><code class="language-rust edition2024">fn main() {
|
||
let x = 5;
|
||
|
||
let x = x + 1;
|
||
|
||
{
|
||
let x = x * 2;
|
||
println!("The value of x in the inner scope is: {x}");
|
||
}
|
||
|
||
println!("The value of x is: {x}");
|
||
}</code></pre>
|
||
<p>This program first binds <code>x</code> to a value of <code>5</code>. Then, it creates a new variable
|
||
<code>x</code> by repeating <code>let x =</code>, taking the original value and adding <code>1</code> so that
|
||
the value of <code>x</code> is <code>6</code>. Then, within an inner scope created with the curly
|
||
brackets, the third <code>let</code> statement also shadows <code>x</code> and creates a new
|
||
variable, multiplying the previous value by <code>2</code> to give <code>x</code> a value of <code>12</code>.
|
||
When that scope is over, the inner shadowing ends and <code>x</code> returns to being <code>6</code>.
|
||
When we run this program, it will output the following:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling variables v0.1.0 (file:///projects/variables)
|
||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
|
||
Running `target/debug/variables`
|
||
The value of x in the inner scope is: 12
|
||
The value of x is: 6
|
||
</code></pre>
|
||
<p>Shadowing is different from marking a variable as <code>mut</code> because we’ll get a
|
||
compile-time error if we accidentally try to reassign to this variable without
|
||
using the <code>let</code> keyword. By using <code>let</code>, we can perform a few transformations
|
||
on a value but have the variable be immutable after those transformations have
|
||
completed.</p>
|
||
<p>The other difference between <code>mut</code> and shadowing is that because we’re
|
||
effectively creating a new variable when we use the <code>let</code> 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:</p>
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span> let spaces = " ";
|
||
let spaces = spaces.len();
|
||
<span class="boring">}</span></code></pre>
|
||
<p>The first <code>spaces</code> variable is a string type, and the second <code>spaces</code> variable
|
||
is a number type. Shadowing thus spares us from having to come up with
|
||
different names, such as <code>spaces_str</code> and <code>spaces_num</code>; instead, we can reuse
|
||
the simpler <code>spaces</code> name. However, if we try to use <code>mut</code> for this, as shown
|
||
here, we’ll get a compile-time error:</p>
|
||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||
</span> let mut spaces = " ";
|
||
spaces = spaces.len();
|
||
<span class="boring">}</span></code></pre>
|
||
<p>The error says we’re not allowed to mutate a variable’s type:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling variables v0.1.0 (file:///projects/variables)
|
||
error[E0308]: mismatched types
|
||
--> src/main.rs:3:14
|
||
|
|
||
2 | let mut spaces = " ";
|
||
| ----- expected due to this value
|
||
3 | spaces = spaces.len();
|
||
| ^^^^^^^^^^^^ expected `&str`, found `usize`
|
||
|
||
For more information about this error, try `rustc --explain E0308`.
|
||
error: could not compile `variables` (bin "variables") due to 1 previous error
|
||
</code></pre>
|
||
<p>Now that we’ve explored how variables work, let’s look at more data types they
|
||
can have.</p>
|
||
</body>
|
||
</html>
|