Chapter 3: More complex types
The introduction distinguishes three collection types and defines control flow as changing how code runs depending on the situation.
After this chapter you will be able to
- Array vector and tuple differences. Distinguish arrays, vectors, and tuples using the basic properties given here.
- Purpose of collections. Explain that a collection holds more than one value together with some sort of order, such as information about cities.
- Array contents and types. Explain how to create an array and why both its element type and length are part of its type.
- Array indexes and slices. Explain zero-based array indexing and how borrowed slices use exclusive or inclusive ranges.
- Vector elements and creation. Describe how a Vec holds elements of one type and how the section introduces creating one with a new-style declaration or the vec! macro.
- Capacity and reallocation. Explain what vector capacity means, what happens when adding items exceeds it, and why an expected size can be supplied in advance.
- Empty tuple and unit type. Explain why a function that returns no value has the empty tuple `()` as its return value, and how a semicolon affects the value returned in the section’s example.
- Tuple contents and access. Describe how a tuple can hold values of different types, how its type is determined, and how to access its items.
- Tuple destructuring patterns. Explain how tuple destructuring creates separate variables, why the pattern must match the tuple, and how `_` can leave an item unnamed. Describe what happens to destructured `String` values in the example.
- Situation-dependent code behavior. Explain that control flow lets code do one thing in one situation and something else in another, such as when a condition is true or a number is even or odd.
- Basic if condition behavior. Explain that an if block runs only when its condition is true; otherwise, Rust skips it.
- Alternative and combined conditions. Describe how else if and else provide alternative branches, and how && and || add conditions using and and or.
- Match arms and syntax. Describe the structure of a match statement: the value being matched, patterns and their actions, fat arrows, and commas between arms.
- Exhaustive cases and wildcard. Explain why a match must account for every possible value and how `_` covers values not handled by more specific patterns.
- First matching arm. Explain that a match stops at its first matching arm, even when another arm could also match.
- Match results and arm types. Explain that a match can supply a variable’s value and that its arms must return the same type; distinguish this from a variable confined to a separate `if` or `else` scope.
- Loop termination and labels. Explain that loop repeats until a break stops it, and that a named loop lets a break exit an outer loop rather than only an inner one.
- While loop condition. Describe how a while loop repeats only while its condition remains true and checks that condition for each repetition.
- For loops and ranges. Explain how a for loop works through a range, including the difference between exclusive and inclusive endpoints and the role of its iteration variable.
- Values returned by break. Explain how break followed by a value can give a loop expression a value that is assigned to a variable.
What it builds on
- Strings (chapter 2) · The earlier discussion of strings and the b prefix.
- Type inference (chapter 1) · type inference
- Declaring variables and code blocks (chapter 1) · Expressions, code blocks, and functions
- Copy types (chapter 2) · The distinction between Copy and non-Copy types
Section by section
Introduction
The introduction distinguishes three collection types and defines control flow as changing how code runs depending on the situation.
- Array vector and tuple differences: Distinguish arrays, vectors, and tuples using the basic properties given here.
Why it matters: These distinctions give you a starting point for recognizing the collection types introduced in the chapter. - Basic meaning of control flow: Explain what control flow means in this introduction.
Why it matters: This gives a plain-language meaning for the chapter’s next topic without requiring its mechanics yet.
Key terms: arrays, vectors, tuples, collection types, control flow
3.1 Collection types
Introduces collections as a way to hold multiple ordered values and explains why arrays are a simple starting point.
- Purpose of collections: Explain that a collection holds more than one value together with some sort of order, such as information about cities.
Why it matters: This gives you a reason to use a collection before considering particular collection types. - Array simplicity tradeoff: Explain why the section starts with arrays: they are simpler than vectors and can be used where memory cannot be allocated, but offer the least functionality to the user.
Why it matters: The tradeoff explains why arrays are introduced before vectors.
Key terms: collections, values, order, arrays, vectors, tiny embedded devices, allocate memory
3.1.1 Arrays
This section explains how to create and use fixed-size Rust arrays, including repeated values, indexing, slices, and ways to identify array types.
- Array contents and types: Explain how to create an array and why both its element type and length are part of its type.
Why it matters: The fixed length explains why arrays of different sizes have different types. - Repeated values and mutable elements: Describe the repeated-value form for creating an array and distinguish changing its elements from changing its size or element type.
Why it matters: Repeated initialization is useful for buffers whose contents change while their capacity stays fixed. - Compiler-reported array types: Describe how a deliberate method error can reveal an array’s type, and state what type the section reports for a b-prefixed string.
Why it matters: Compiler messages can make an unfamiliar array type visible. - Array indexes and slices: Explain zero-based array indexing and how borrowed slices use exclusive or inclusive ranges.
Why it matters: Index and range boundaries determine exactly which array values a slice contains.
Key terms: array, [type; number], [value; number], mut, byte buffers, compiler, method not found, b prefix, byte array, u8
3.1.2 Vectors
This section introduces vectors as resizable collections, explains their element types and common ways to create them, and shows how capacity affects allocation.
- Vectors compared with arrays: Distinguish vectors from arrays in terms of size and flexibility.
Why it matters: This distinction helps you choose a collection when its number of items might change. - Vector elements and creation: Describe how a Vec holds elements of one type and how the section introduces creating one with a new-style declaration or the vec! macro.
Why it matters: Reading the element type tells you what a vector can hold and what you can add to it. - Capacity and reallocation: Explain what vector capacity means, what happens when adding items exceeds it, and why an expected size can be supplied in advance.
Why it matters: Estimating capacity can save the work of repeatedly moving a growing vector’s items. - Vector slicing and conversion: State that a vector can be sliced like an array and that .into() can convert an array to a Vec when the desired target is declared.
Why it matters: These similarities let you reuse familiar array operations and turn an array into a resizable collection.
Key terms: array, vector, Vec, Vec<String>, <>, vec!, type inference, .push(), capacity, reallocation
3.1.3 Tuples
This section explains tuple values and types, the empty tuple as a function return value, and how to take tuple values apart with destructuring.
- Empty tuple and unit type: Explain why a function that returns no value has the empty tuple `()` as its return value, and how a semicolon affects the value returned in the section’s example.
Why it matters: It explains why a function can return `()` even when it creates a value inside its body. - Tuple contents and access: Describe how a tuple can hold values of different types, how its type is determined, and how to access its items.
Why it matters: It helps you read tuple types and retrieve a particular value from a tuple. - Tuple destructuring patterns: Explain how tuple destructuring creates separate variables, why the pattern must match the tuple, and how `_` can leave an item unnamed. Describe what happens to destructured `String` values in the example.
Why it matters: It lets you take values out of a tuple while accounting for both the required pattern and ownership of its contents.
Key terms: tuple, empty tuple, unit type, semicolon, dot notation, destructuring, pattern, String, Copy type, _
3.2 Control flow
Introduces control flow as choosing what code does in different situations.
- Situation-dependent code behavior: Explain that control flow lets code do one thing in one situation and something else in another, such as when a condition is true or a number is even or odd.
Why it matters: This is the basic idea behind making a program respond differently to different conditions.
Key terms: control flow, condition
3.2.1 Basic control flow
This section introduces basic Rust control flow with if, else if, else, and combined conditions.
- Basic if condition behavior: Explain that an if block runs only when its condition is true; otherwise, Rust skips it.
Why it matters: This is the starting point for deciding which code runs. - Comparison and if syntax: Distinguish == for comparison from = for assignment, and describe the section’s rule about parentheses around an if condition.
Why it matters: These distinctions help you read and write the conditions in the examples. - Alternative and combined conditions: Describe how else if and else provide alternative branches, and how && and || add conditions using and and or.
Why it matters: Together, branches and combined tests let a program choose among more than one outcome.
Key terms: if, condition, {}, ==, =, else if, else, &&, ||
3.2.2 Match statements
The section explains how Rust match statements select among patterns, require complete coverage and consistent arm types, and support guards and value binding.
- Match arms and syntax: Describe the structure of a match statement: the value being matched, patterns and their actions, fat arrows, and commas between arms.
Why it matters: This is the basic form needed to read or write the section’s examples. - Exhaustive cases and wildcard: Explain why a match must account for every possible value and how `_` covers values not handled by more specific patterns.
Why it matters: An uncovered case prevents the code from compiling. - First matching arm: Explain that a match stops at its first matching arm, even when another arm could also match.
Why it matters: Overlapping patterns can compile while producing a different result from the one you intended. - Pattern guards and tuple patterns: Describe how a match can use a tuple pattern or an `if` guard to make a more specific choice.
Why it matters: These forms let an arm express a more specific situation than a single simple value. - Match results and arm types: Explain that a match can supply a variable’s value and that its arms must return the same type; distinguish this from a variable confined to a separate `if` or `else` scope.
Why it matters: This explains why some match-based assignments fail to compile while the shown block-scoped `if` and `else` example works. - Named matched values: Explain what `@` adds to a match pattern when an arm needs to use the value it matched.
Why it matters: It lets an arm refer to the particular number that matched rather than merely recognizing it.
Key terms: match, pattern, fat arrow, arm, _, wildcard, tuple, match guard, type, scope
3.2.3 Loops
This section explains how Rust’s loop, while, and for loops repeat work, how to stop them, and how a loop can produce a value.
- Loop termination and labels: Explain that loop repeats until a break stops it, and that a named loop lets a break exit an outer loop rather than only an inner one.
Why it matters: It helps you tell whether a loop will finish, especially when loops are nested. - While loop condition: Describe how a while loop repeats only while its condition remains true and checks that condition for each repetition.
Why it matters: A while loop expresses repetition in terms of a condition rather than an explicit break. - For loops and ranges: Explain how a for loop works through a range, including the difference between exclusive and inclusive endpoints and the role of its iteration variable.
Why it matters: Range endpoints determine how many repetitions occur and which values the loop body can use. - Unused for loop variables: Distinguish using _ when a for loop does not need its current value from prefixing a named variable with _ to avoid an unused-variable warning.
Why it matters: It lets you write a repetition-only loop without an unnecessary variable warning. - Values returned by break: Explain how break followed by a value can give a loop expression a value that is assigned to a variable.
Why it matters: It shows that a loop can do more than repeat actions: it can supply a value to a variable. - Full comparison with for: Explain why the section uses a for loop for the colors problem instead of matching and breaking at the first condition.
Why it matters: Choosing a loop that visits every item matters when an early match would skip comparisons.
Key terms: loop, break, tick, while loop, for loop, range, exclusive range, inclusive range, _, _number
3.3 Summary
Where this is used later
- Other collections (chapter 6) · Introduces collection types.
- HashMap (and BTreeMap) (chapter 6) · The idea of a collection holding multiple items.
- (chapter intro) (chapter 8) · Introduces collection types.
- (chapter intro) (chapter 16) · Introduces arrays.
- Const generics (chapter 16) · Arrays and their lengths
- Enums to use multiple types (chapter 4) · Vec elements have one type.
- Some other ways to do pattern matching (chapter 5) · Assumes familiarity with vectors.
- VecDeque (chapter 6) · The basic Vec collection and its indexed items.
Concepts explained in this chapter
- tupleA tuple is a fixed-size Rust composite value whose elements may have different types and are accessed by position.
- arrayAn array is a fixed-size Rust collection whose length is known at compile time and whose elements have one type.
- intervalAn interval is a connected set or span of values between specified lower and upper endpoints, with endpoint inclusion determined by its definition.
- blank identifierA blank identifier is a language-defined name or symbol that receives or matches a value without binding it to a usable variable.
- patternPattern is a Rust string-matching trait implemented by supported search patterns such as string slices, characters, and closures.
- vectorA vector is Rust's growable, heap-allocated sequence type whose elements share a type.
- pattern matchingPattern matching is the process of comparing a value against structural patterns and handling the matching case.
- loopA for loop is Rust iteration syntax that repeatedly executes a block for each item produced by an iterable value.
- destructuring assignmentDestructuring is Rust syntax that binds the components of a composite value to separate variables through a matching pattern.
- unit typeA unit type is a type with exactly one value, commonly written (), that represents the absence of meaningful information or a meaningful result.
- slicingA slice is a dynamically sized borrowed view of a contiguous sequence of values.
- dotted notationDot notation is Rust syntax that accesses a tuple element or object member by placing a period before its selector.
- semicolonA semicolon is Rust syntax that terminates an expression statement and changes the value behavior of a block expression.
- indexingIndexing selects elements in an ordered collection by their numeric positions.
- guardA match guard is an additional Boolean condition attached to a Rust match arm after its pattern matches.
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.
