Length | Signed | Unsigned |
---|---|---|
8-bit | i8 |
u8 |
16-bit | i16 |
u16 |
32-bit | i32 |
u32 |
64-bit | i64 |
u64 |
128-bit | i128 |
u128 |
arch | isize |
usize |
Signed variants can store numbers from -(2n - 1) to 2n - 1 - 1 inclusive
i8
: -(27) to 27 - 1, which equals -128 to 127.u8
: 0- 2n - 1, that is 0 to 28 - 1, which equals 0 to 255Rust uses two’s complement wrapping to handle integer overflow silently. However, it offers explicit ways to manage overflow:
wrapping_*
methods: Always wrap values (e.g., wrapping_add
).checked_*
methods: Return None if overflow occurs.overflowing_*
methods: Return the result along with a boolean indicating overflow.saturating_*
methods: Clamp the result to the type’s minimum or maximum value.Types: f32
and f64
(primitive types)
f32
: single-precision floatf64
: double precision floatBoolean: bool
Character: char
1
char
type is four bytes in size and represents a Unicode Scalar Value.Group values of different types:
Fixed-length collections of the same type:
Short-hand:
value of elements
; then number of elements
You can access elements of an array using indexing:
x[0]
)Variables in Rust are immutable by default:
Use the mut
keyword to make variables mutable:
Declared with const
and are always immutable:
Shadowing allows reusing a variable name:
mut
and Shadowingmut |
shadowing | |
---|---|---|
Type | Same type | Can change type (use of let ) |
Use of let |
When first declared | All instances of variable use |
Functions can accept parameters/arguments:
Return the last expression from the function body:
if
Expressionsfn main() {
let number = 3;
if number < 5 {
println!("Condition is true");
} else {
println!("Condition is false");
}
}
if
with a Boolean as its condition.else if
for Multiple Conditionsfn main() {
let number = 6;
if number % 4 == 0 {
println!("Divisible by 4");
} else if number % 3 == 0 {
println!("Divisible by 3");
} else {
println!("Not divisible by 4 or 3");
}
}
true
condition, and once it finds one, it doesn’t even check the rest.if
in a let
Statementif
is an expression, hence we can use it on the RHS of a let
statement to assign the outcome to a variable
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}
number
variable will be bound to a value based on the outcome of the if
expressionif
must be the same typefn main() {
let condition = true;
let number = if condition { 5 } else { "six" };
println!("The value of number is: {number}");
}
This throws an error because the types of the values in the if
and else
blocks are different.
loop
loop
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("Result: {result}");
}
break
or return
is never executed.break
expression and a return
expression as having the value unit, or ()
.while
LoopWhile a condition evaluates to true
, the code runs; otherwise, it exits the loop.
for
Loopfor
are the most commonly used loop construct in Rust.
loop
Labels to DisambiguateLabeling loops when we have loops inside loops 1
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}
The break 'counting_up;
statement will exit the outer loop.
wrapping_*
methods: Always wrap values (e.g., wrapping_add
).checked_*
methods: Return None if overflow occurs.overflowing_*
methods: Return the result along with a boolean indicating overflow.saturating_*
methods: Clamp the result to the type’s minimum or maximum value.Feature | Rust | R | Python | C/C++ |
---|---|---|---|---|
Arrays | Fixed-size, homogeneous types, defined as [T; N] . |
Homogeneous data, multidimensional (using array() ). |
Homogeneous data, implemented via NumPy (numpy.array ). |
Fixed-size, homogeneous, defined as T array[N] . |
Vectors | A growable collection with Vec<T> . |
1D array, typically with c() or vector() . |
Lists mimic vectors, but for true vector operations, use NumPy arrays. | No native vector, use std::vector from the Standard Library (C++). |
Tuples | Fixed-length, immutable collection: (i32, f64) . |
Not commonly used, lists behave like tuples. | Immutable, ordered sequence: (1, 2, "text") . |
Use std::tuple (C++17+) or structures. |
Matrices | Not native; use nested Vec<Vec<T>> or external libraries like nalgebra . |
2D structure (matrix() ). Can extend to 3D with array() . |
Implemented with NumPy as 2D arrays: numpy.matrix or numpy.array . |
2D arrays as T matrix[rows][cols] or use libraries like Eigen in C++. |
Mutability | Vectors (Vec<T> ) are mutable; tuples are immutable. |
Vectors are mutable; matrices can be altered in-place. | Lists and arrays are mutable; tuples are immutable. | Arrays and vectors (std::vector ) are mutable. Tuples are immutable in C++17+. |
Indexing | 0-based indexing (e.g., x[0] ). |
1-based indexing (e.g., x[1] ). |
0-based indexing (e.g., x[0] ). |
0-based indexing (e.g., x[0] ). |
Size Flexibility | Arrays are fixed, vectors grow dynamically. | Vectors and lists are dynamic. Arrays and matrices have fixed sizes. | Lists and NumPy arrays are dynamic; tuples are fixed size. | Arrays are fixed; std::vector is dynamic. |
A contiguous mutable array type, written as Vec<T>
, short for ‘vector’.
Temperature Conversion:
Write a function to convert temperatures between Fahrenheit and Celsius.
Fibonacci Sequence:
Generate the nth Fibonacci number using recursion.
Christmas Carol:
Print the lyrics to “The Twelve Days of Christmas” with loops to reduce repetition.