Chapter 2: Memory, variables, and ownership
Introduces Rust’s focus on memory use and ownership without yet explaining the memory mechanisms.
After this chapter you will be able to
- Memory and ownership focus. Explain that Rust makes programmers pay attention to how a program uses memory and to ownership—who owns the data.
- Stack and heap storage. Explain why fixed-size values can go on the stack, while data without a known compile-time size goes on the heap and is reached through a pointer on the stack.
- References and borrowed values. Describe what a Rust reference points to, how `&` creates one, and why referring to a value does not transfer ownership. State that references can themselves be referenced, producing different types.
- String ownership and string slices. Distinguish String from &str by explaining ownership and what each represents. Describe why a String can be grown or changed while a &str is a view into data.
- String creation and conversion. Describe the section’s ways to create a String from text, including String::from, .to_string(), and format!. Explain why .into() may need the intended output type made clear.
- Const and static declarations. Distinguish const and static from let declarations and from each other at the level explained here.
- Compile-time creation limits. Explain why the section says not to make every value global, including its heap-memory limitation.
- References to local Strings. Explain why a function cannot return a reference to a String it created locally, and contrast that reference with passing around an owned String.
- Mutable reference syntax and type. Explain that &mut creates a mutable reference, which can be used to change data, and that a reference to an i32 has the type &mut i32 rather than i32.
- Dereferencing to change a value. Explain why adding directly to num_ref does not change my_number, and describe how * reaches the value behind the mutable reference so it can be changed.
- Immutable and mutable reference rules. State that Rust permits any number of immutable references, but only one mutable reference, and does not permit mutable and immutable references together.
- Single Mutable Reference Analogy. Explain how the manager editing a presentation represents someone using a mutable reference without owning the data, and why the arrangement is fine when nobody else is looking at it.
- Shared immutable references. Explain why any number of people can have immutable references to the same data at once: they can see it, but none can change it.
- Conflicting mutable and immutable borrows. Explain why using an immutable reference while a mutable borrow is still active is a problem: the value could change unexpectedly for readers of the immutable reference.
- Mutable borrow ending after use. Explain why the example can change a value through a mutable reference and later print it through an immutable reference: the mutable reference is not used again, so its borrow has ended.
- References reveal shadowed values. Explain why the example prints Austria, 8 rather than 8, 8: country_ref still refers to the original String after country is shadowed by an i32.
- Ownership when passing Strings. Trace what happens when a String is passed by value to a function that does not return it, and explain why the caller cannot use it afterward.
- Borrowed function parameters. Distinguish what a function can do with a &String versus a &mut String, and explain what both forms mean for ownership.
- Mutable owned parameters. Explain why mut name: String is not a mutable reference and why the caller’s variable need not be mutable for the function to change its newly owned String.
- Automatic copying and moves. Explain that Rust automatically copies a Copy type when passing it to a function, whereas passing a String by value moves it because String is not Copy.
- Explicit cloning of Strings. Explain how calling .clone() lets a String be passed by value to a function while keeping the original available, and distinguish this from automatic copying.
- References instead of repeated clones. Justify using an immutable reference rather than repeatedly cloning a String when the function does not need ownership.
- Uninitialized variable rules. Describe how to declare a variable without a value and when Rust allows it to be used.
- Escapes and raw strings. Explain how escape sequences affect printed text and when a raw string makes text easier to write.
- Positional and named placeholders. Explain how indices or names select values in a printed string.
- Padding and alignment format. Explain how the section’s format options control padding, alignment, and length.
What it builds on
- Declaring variables and code blocks (chapter 1) · Uses variable declarations such as `let my_variable = 8`.
- “Hello, World!” and printing (chapter 1) · The comparison of format! with println! assumes familiarity with printing.
- Type inference (chapter 1) · Introduces type inference, which these declarations do not use.
- Shadowing (chapter 1) · The earlier introduction to shadowing.
- Mutability (changing) (chapter 1) · What declaring a variable mutable means.
Section by section
Introduction
Introduces Rust’s focus on memory use and ownership without yet explaining the memory mechanisms.
- Memory and ownership focus: Explain that Rust makes programmers pay attention to how a program uses memory and to ownership—who owns the data.
Why it matters: This focus frames the memory and ownership ideas developed in the chapter.
Key terms: memory, ownership
2.1 The stack, the heap, pointers, and references
Explains why Rust uses the stack, heap, and pointers, then introduces references as borrowed access to another value’s memory.
- Stack and heap storage: Explain why fixed-size values can go on the stack, while data without a known compile-time size goes on the heap and is reached through a pointer on the stack.
Why it matters: This gives you a picture of where values live and how a program finds heap data. - References and borrowed values: Describe what a Rust reference points to, how `&` creates one, and why referring to a value does not transfer ownership. State that references can themselves be referenced, producing different types.
Why it matters: It helps you distinguish looking at a value’s data from owning that data.
Key terms: stack, heap, pointer, compile time, reference, borrow, own, &
2.2 Strings
This section distinguishes borrowed string slices from owned strings and shows how Rust represents and creates them.
- String ownership and string slices: Distinguish String from &str by explaining ownership and what each represents. Describe why a String can be grown or changed while a &str is a view into data.
Why it matters: The distinction helps you tell whether a string value owns text or merely views it. - References to dynamically sized str: Explain why Rust uses &str rather than a bare str in the examples: a str can have different sizes, while the compiler knows the size of a reference’s pointer.
Why it matters: This explains why the reference marker in &str is necessary, not just a naming convention. - UTF-8 string contents: State that both String and &str use UTF-8 and can contain text from different languages, including emoji, even when a command line cannot display it.
Why it matters: A display problem in a terminal does not mean Rust cannot hold the text. - String creation and conversion: Describe the section’s ways to create a String from text, including String::from, .to_string(), and format!. Explain why .into() may need the intended output type made clear.
Why it matters: Choosing a construction method—and clarifying the target type when needed—lets you obtain an owned String.
Key terms: String, &str, string slice, owned, str, dynamically sized, reference, stack, UTF-8, Unicode
2.3 const and static
Introduces const and static as typed, usually global declarations, explains how they differ, and outlines when they can be used.
- Const and static declarations: Distinguish const and static from let declarations and from each other at the level explained here.
Why it matters: These distinctions help you recognize what each declaration promises without treating them as ordinary let variables. - Global access and lifetime: Explain why a const or static declared outside main can be used by a function without receiving it as input.
Why it matters: It explains why the example function can use NUMBER_OF_MONTHS without an argument. - Compile-time creation limits: Explain why the section says not to make every value global, including its heap-memory limitation.
Why it matters: Global convenience does not mean every runtime value can be declared this way.
Key terms: const, static, let, type inference, fixed memory location, global, NUMBER_OF_MONTHS, dropped, compile time, heap
2.4 More on references
This section shows that multiple references can view an owned String, but a function cannot return a reference to a String that disappears when the function ends.
- Shared views of a String: Explain that a String owns its data and that multiple &String references can view the same data without taking ownership.
Why it matters: This separates viewing a String from owning its data. - References to local Strings: Explain why a function cannot return a reference to a String it created locally, and contrast that reference with passing around an owned String.
Why it matters: It explains the memory mistake Rust prevents when a reference would outlive the data it views.
Key terms: String, &String, reference, owns its data, ownership, code block
2.5 Mutable references
This section introduces mutable references and shows how dereferencing lets you change the value they refer to.
- Mutable reference syntax and type: Explain that &mut creates a mutable reference, which can be used to change data, and that a reference to an i32 has the type &mut i32 rather than i32.
Why it matters: The distinction between a value and a mutable reference to it is needed to understand how the value gets changed. - Dereferencing to change a value: Explain why adding directly to num_ref does not change my_number, and describe how * reaches the value behind the mutable reference so it can be changed.
Why it matters: Dereferencing explains how code changes the underlying number rather than trying to add to a reference.
Key terms: mutable reference, &mut, &mut i32, dereferencing, *, referencing, &
2.5.1 Rust’s reference rules
States Rust’s rules for immutable and mutable references and explains why simultaneous reading and changing could cause problems.
- Immutable and mutable reference rules: State that Rust permits any number of immutable references, but only one mutable reference, and does not permit mutable and immutable references together.
Why it matters: These rules let you tell which combinations of references Rust allows. - Reason for reference restrictions: Explain why immutable references can be numerous while mutable references are restricted: viewing data does not change it, but changing data while other references read it could cause problems.
Why it matters: The reason behind the rules makes them easier to remember.
Key terms: immutable references, mutable references, viewing data, change the data
2.5.2 Situation 1: Only one mutable reference
Uses a shared-presentation analogy to show why one mutable reference can safely make changes when nobody else is viewing the data.
- Single Mutable Reference Analogy: Explain how the manager editing a presentation represents someone using a mutable reference without owning the data, and why the arrangement is fine when nobody else is looking at it.
Why it matters: The analogy makes the difference between owning data and temporarily being able to change it easier to picture.
Key terms: mutable reference, own the data
2.5.3 Situation 2: Only immutable references
This subsection uses a presentation analogy to explain why many immutable references can exist at the same time.
- Shared immutable references: Explain why any number of people can have immutable references to the same data at once: they can see it, but none can change it.
Why it matters: This makes the distinction between sharing data for reading and changing it easier to remember.
Key terms: immutable reference, data
2.5.4 Situation 3: The problem situation
This section explains why an active mutable borrow cannot overlap with an immutable borrow, and why code can work when the mutable borrow ends before the immutable one is used.
- Conflicting mutable and immutable borrows: Explain why using an immutable reference while a mutable borrow is still active is a problem: the value could change unexpectedly for readers of the immutable reference.
Why it matters: This explains the problem Rust’s reference rule is designed to prevent. - Mutable borrow ending after use: Explain why the example can change a value through a mutable reference and later print it through an immutable reference: the mutable reference is not used again, so its borrow has ended.
Why it matters: This helps you see why a later immutable reference can be valid even when a mutable reference appeared earlier in the code.
Key terms: mutable reference, immutable borrow, mutable borrow, immutable reference, number_change
2.6 Shadowing again
This section uses a reference to show that shadowing blocks access to an earlier binding without destroying its value.
- References reveal shadowed values: Explain why the example prints Austria, 8 rather than 8, 8: country_ref still refers to the original String after country is shadowed by an i32.
Why it matters: A reference makes it possible to see that a shadowed value still exists even though its original name now refers to something else.
Key terms: shadowing, reference, String, i32
2.7 Giving references to functions
This section explains how passing a String to a function transfers ownership, while passing a reference lets the function use the String without owning it.
- Ownership when passing Strings: Trace what happens when a String is passed by value to a function that does not return it, and explain why the caller cannot use it afterward.
Why it matters: This explains why a second attempt to pass the same String produces a moved-value error. - Borrowed function parameters: Distinguish what a function can do with a &String versus a &mut String, and explain what both forms mean for ownership.
Why it matters: References let a function use a String without requiring the caller to give it away. - Mutable owned parameters: Explain why mut name: String is not a mutable reference and why the caller’s variable need not be mutable for the function to change its newly owned String.
Why it matters: This prevents confusing permission to change a function’s owned parameter with borrowing a caller’s data mutably.
Key terms: owner, move, use of moved value, String, &String, &mut String, borrows, reference, mut string_to_add_hungary_to, mut country: String
2.8 Copy types
This section explains why Copy values are duplicated automatically, how to check whether a type is Copy, and when to use cloning or references instead.
- Automatic copying and moves: Explain that Rust automatically copies a Copy type when passing it to a function, whereas passing a String by value moves it because String is not Copy.
Why it matters: This distinction explains why an i32 can be passed repeatedly to a function but the same String cannot be passed by value twice. - Checking Copy in documentation: Describe how to check a type’s Trait Implementations in its documentation to see whether it implements Copy.
Why it matters: Checking the type’s listed traits helps you predict whether passing it by value will copy it. - Explicit cloning of Strings: Explain how calling .clone() lets a String be passed by value to a function while keeping the original available, and distinguish this from automatic copying.
Why it matters: Cloning is an option when a function takes ownership and you still need the original String afterward. - References instead of repeated clones: Justify using an immutable reference rather than repeatedly cloning a String when the function does not need ownership.
Why it matters: Choosing a reference avoids unnecessary copies while preserving access to the original value.
Key terms: Copy types, move semantics, copy semantics, String, Trait Implementations, Copy, Clone, .clone(), immutable reference, &
2.9 Variables without values
This section explains how to declare a variable before assigning it a value, and why that can be useful when the value comes from a code block.
- Uninitialized variable rules: Describe how to declare a variable without a value and when Rust allows it to be used.
Why it matters: It lets you declare a name before its value is ready without accidentally using an unset value. - Initialization across code blocks: Explain why a variable might be declared outside a code block but given its value inside the block, and why that first assignment does not require mut.
Why it matters: This pattern keeps a value available after the block that supplies it, without making the variable mutable.
Key terms: uninitialized variable, let, initialized, code block, my_number, mut
2.10 More about printing
This section explains ways to print strings, bytes, addresses, numbers, and formatted values in Rust, then reinforces ownership with a computer-sharing analogy.
- Escapes and raw strings: Explain how escape sequences affect printed text and when a raw string makes text easier to write.
Why it matters: These choices help you print special characters without losing track of backslashes and quotes. - Byte and Unicode printing: Describe the byte-string prefix and the Unicode escape shown in the section.
Why it matters: These forms distinguish printing a character from printing its byte values or specifying it by Unicode number. - Addresses and number bases: Describe what {:p} prints and identify the number representations illustrated alongside it.
Why it matters: It helps you recognize when printed output is a memory address rather than an ordinary value. - Positional and named placeholders: Explain how indices or names select values in a printed string.
Why it matters: Explicit placeholders let you control which value appears at each point in a message. - Padding and alignment format: Explain how the section’s format options control padding, alignment, and length.
Why it matters: Reading these pieces lets you understand and adjust more elaborate printed output. - Ownership through computer sharing: Explain how the computer-sharing comparison distinguishes immutable references, mutable references, ownership transfer, and Copy types.
Why it matters: The comparison ties together the chapter’s distinctions between sharing, changing, transferring, and copying a value.
Key terms: escape, raw, r#, bytes, ASCII, b, Unicode escape, \u{}, {:p}, pointer address
2.11 Summary
Where this is used later
- Arrays (chapter 3) · The earlier discussion of strings and the b prefix.
- Types of &str (chapter 10) · Assumes familiarity with String and &str.
- char (chapter 20) · Strings and &str.
- The From trait (chapter 7) · The later treatment of From expands on the conversion mentioned here.
- Mutable statics (chapter 16) · Revisits static values and their mutability.
- (chapter intro) (chapter 16) · Introduces const in Rust.
- Const functions (chapter 16) · The earlier introduction to const values.
- Unsafe Rust (chapter 16) · Assumes the earlier distinction between const and static.
Concepts explained in this chapter
- referenceReferencing is the operation of creating a Rust reference with the & operator.
- ownershipOwnership is Rust's rule-based model in which each value has a responsible binding that controls the value's lifetime and access.
- mutable referenceA mutable reference is a Rust reference that permits modification of its referent and must be the sole active reference to that referent.
- Copy traitA copy type is a Rust type whose values can be duplicated implicitly by copying their bits rather than transferring ownership.
- moveMove semantics is the behavior in which transferring a non-Copy value transfers its ownership and prevents use of the original binding.
- referenceAn immutable reference is a Rust reference through which the referent cannot be modified and which can coexist with other immutable references.
- println! macroThe println! macro formats its arguments and writes the resulting text followed by a newline to standard output.
- Unicode escapeA Unicode escape is a string-literal notation that represents a Unicode character using a hexadecimal code point.
- escape sequenceAn escape sequence is a character sequence in a string literal that represents a special character or encoding instruction.
- formattingFormatting is the arrangement or transformation of content, data, or code according to specified structural, stylistic, or presentation conventions.
- ownership transferOwnership transfer is the movement of a value's controlling ownership from one binding or function to another.
- printPrinting is the operation of writing textual or formatted data to an output stream.
- slicingA slice is a dynamically sized borrowed view of a contiguous sequence of values.
- stringA string is a programming-language value representing an ordered sequence of characters or character units as text.
- dynamically sized typeA dynamically sized type is a type whose size is not known at compile time and may vary between values.
- format! macroThe format! macro constructs a formatted String instead of writing formatted output.
- heapThe heap is a region of memory used for dynamically allocated data whose size or lifetime is not limited to a call frame.
- stackThe stack is a memory region that stores values with a known size and releases them in last-in, first-out order as execution leaves scopes or functions.
- static fieldA Rust program item representing a value stored at a fixed memory location for the entire program lifetime.
- const qualifierA language feature that marks a value, binding, or access path as constant, restricting reassignment or modification according to the language’s rules.
- shadowingShadowing is the Rust language feature that creates a new variable with the same name as an existing variable, hiding the earlier binding within the current scope.
- DebugDebug is the Rust trait for producing programmer-oriented representations of values.
- DisplayDisplay printing formats a Rust value using its user-facing Display formatting behavior.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
