Variable bindings, Constants & Statics
⭐️ In Rust, variables are immutable by default, so we call them Variable bindings. To make them mutable, the mut
keyword is used.
⭐️ Rust is a statically typed language; it checks data types at compile-time. But it doesn’t require you to actually type it when declaring variable bindings. In that case, the compiler checks the usage and sets a better data type for it. But for constants and statics, you must annotate the type. Types come after a colon(:
).
💭 In the following examples, we will use data types like
bool
,i32
,i64
andf64
. Don’t worry about them for now; they’ll be discussed later.
- Variable bindings
The let
keyword is used in binding expressions. We can bind a name to a value or a function. Also, because the left-hand side of a let expression is a “pattern”, you can bind multiple names to a set of values or function values.
let a; // Declaration; without data type
a = 5; // Assignment
let b: i8; // Declaration; with data type
b = 5;
let t = true; // Declaration + assignment; without data type
let f: bool = false; // Declaration + assignment; with data type
let (x, y) = (1, 2); // x = 1 and y = 2
let mut z = 5;
z = 6;
let z = { x + y }; // z = 3
let z = {
let x = 1;
let y = 2;
x + y
}; // z = 3
- Constants
The const
keyword is used to define constants and after the assignment their values are not allowed to change. They live for the entire lifetime of a program but has no fixed address in the memory.
const N: i32 = 5;
- Statics
The static
keyword is used to define a “global variable” type facility. There is only one instance for each value, and it’s at a fixed location in memory.
static N: i32 = 5;
💭 While you need constants, always use
const
, instead ofstatic
. It’s pretty rare that you actually want a memory location associated with your constant, and using a const allows for optimizations like constant propagation, not only in your crate but also in downstream crates.
Variable Shadowing
Sometimes, while dealing with data, initially we get them in one unit but need to transform them into another unit for further processing. In this situation, instead of using different variable names, Rust allows us to redeclare the same variable with a different data type and/ or with a different mutability setting. We call this Shadowing.
fn main() {
let x: f64 = -20.48; // float
let x: i64 = x.floor() as i64; // int
println!("{}", x); // -21
let s: &str = "hello"; // &str
let s: String = s.to_uppercase(); // String
println!("{}", s) // HELLO
}
👨🏫 Before going to the next…
-
The naming convention for the variable bindings is using the
snake_case
. But, for constants and statics, we should follow theSCREAMING_SNAKE_CASE
. -
Usually, constants and statics are placed at the top of the code file, outside the functions (after module imports/
use
declarations).
const PI: f64 = 3.14159265359;
fn main() {
println!("π value is {}", PI);
}