3.3.0. Before We Begin
Welcome to Chapter 3 of this Rust self-study series. It has 6 sections:
- Variables and Mutability
- Data Types: Scalar Types
- Data Types: Compound Types (this article)
- Functions and Comments
- Control Flow:
if else - Control Flow: Loops
Through the guessing game in Chapter 2 (beginners who have not read it are strongly encouraged to take a look), you should now have learned the basic Rust syntax. In Chapter 3, we will go one level deeper and learn the general programming concepts in Rust.
3.3.1. An Introduction to Compound Types
- Compound types can group multiple values into a single type.
- Rust provides two basic compound types: tuples and arrays.
3.3.1. Tuple
Tuple characteristics:
- A tuple can group multiple values of different types into a single type.
- Tuples have a fixed length: once declared, they cannot change.
Creating a tuple:
- Place the values inside parentheses, separated by commas.
- Each position in the tuple corresponds to a type, and the types of the tuple's elements do not have to be the same.
fn main(){
let tup: (u32, f32, i64) = (6657, 0.0721, 114514);
println!("{},{},{}", tup.0, tup.1, tup.2);
// Output: 6657,0.0721,114514
}
Getting tuple element values:
- You can use pattern matching to destructure a tuple and obtain its element values.
fn main(){
let tup: (u32, f32, i64) = (6657, 0.0721, 114514);
let (x, y, z) = tup;
println!("{},{},{}", x, y, z);
// Output: 6657,0.0721,114514
}
Accessing tuple elements:
- Use dot notation after the tuple variable, followed by the element index.
println!("{},{},{}", tup.0, tup.1, tup.2);
3.3.2. Arrays
Array characteristics:
- Every element in an array must have the same type.
- Arrays can also store multiple values in a single type.
- Arrays have a fixed length.
Declaring an array:
- Put the values inside square brackets, separated by commas.
let a = [1, 1, 4, 5, 1, 4];
Uses for arrays:
- If you want your data on the stack instead of the heap, or you want to guarantee a fixed number of elements, arrays are a better choice.
- Arrays are less flexible than vectors (which we will discuss later).
- Vectors are provided by the standard library, while arrays are built into the language and available through the prelude module, which is also part of the standard library.
- A vector's length can change.
- If you are unsure whether to use an array or a vector, you probably should use a vector.
Array type syntax:
- The type of an array is written as
[type; length].
let machine: [u32; 4] = [6, 6, 5, 7];
Another way to declare an array:
- If every element in the array has the same value, you can:
- Specify the initial value inside square brackets
- Follow it with a
; - Then add the array length
let a = [3; 2];
let b = [3, 3, 3];
In this example, a and b are equivalent.
Accessing array elements:
- Arrays are a single contiguous block of memory allocated on the stack.
- You can use an index to access an array element.
let machine = [6, 6, 5, 7];
let wjq = machine[0];
- If the index is out of bounds:
- Rust may detect it at compile time in cases where the compiler can prove the error
- Otherwise, it will panic at runtime, because Rust does not allow the program to keep reading memory at that address
An array is backed by a contiguous block of memory. Suppose the first element of an array is at memory position x; then the second element is located at x + the size of the first element, and so on.
If the index is larger than the actual length of the array, the program will read memory outside the array, and that memory may contain anything. In C, there is no bounds checking at all. In C++, ordinary arrays do not have it either; only std::array does. In Rust, bounds checking is enforced.
| Feature | C | C++ | Rust |
|---|---|---|---|
| Memory model | Contiguous | Contiguous | Contiguous |
| Safety | No bounds checking |
std::array has bounds checking; ordinary arrays do not |
Bounds checking is enforced |
| Dynamic arrays | Manual memory management required | std::vector |
Vec |
| Multidimensional arrays | Yes | Yes | Yes |
| Special abilities | Simple and efficient | Rich STL containers | Ownership and borrow checking |
But Rust only performs simple bounds checks on arrays. If the code becomes slightly more complex, the compiler may not be able to check it at compile time, so the check has to happen at runtime.
let a = 5;
let machine = [6, 6, 5, 7];
let wjq = machine[a];
This code will compile, but it will panic at runtime if a is out of bounds.
let a = [1, 9, 10, 4, 5];
let machine = [6, 6, 5, 7];
let wjq = machine[a[4]];
Depending on how much the compiler can determine ahead of time, this code may also fail early, but if it is not caught at compile time, it will panic at runtime.
Top comments (0)