Basic Data
1. Welcome and Icebreaker:
Welcome back!
If you could create a new data type to represent anything you wanted, what would it be, and what kind of values would it hold?
2. Outline the Session:
Here’s our plan for this session:
- Concept Explanation: We’ll discuss the common scalar and compound data types in Rust.
- Live Coding Demonstration: We’ll write code examples to demonstrate how to declare and use variables with different types.
- Tasks: I will challenge you in task section.
Learning Outcomes: By the end of this session, you will be able to:
- Understand and use Rust’s basic data types (integers, floats, booleans, characters, strings, tuples, arrays).
- Declare variables using
let, and understand mutability withmut. - Understand type inference and explicit type annotations.
Expectations: Don’t hesitate to ask questions! Experimenting with the code is highly encouraged.
3. Concept Explanation:
Rust is a statically typed language. This means that the compiler must know the type of every variable at compile time. However, the compiler is often smart enough to infer the type based on how you use the variable. You can also explicitly specify the type if you wish.
Here are some of the core data types in Rust:
- Scalar Types: Represent a single value.
- Integers: Whole numbers. Rust provides signed (can be negative) and unsigned (non-negative) integers of various sizes:
i8,i16,i32,i64,i128: Signed integers (8, 16, 32, 64, and 128 bits, respectively).u8,u16,u32,u64,u128: Unsigned integers.isize,usize: Their size depends on the architecture of your computer (usually 32 or 64 bits). Used for indexing collections.
- Floating-Point Numbers: Numbers with decimal points.
f32: 32-bit floating-point number (single precision).f64: 64-bit floating-point number (double precision). This is the default for floating-point literals.
- Booleans: Represent truth values.
bool: Can be eithertrueorfalse.
- Characters: Represent a single Unicode character.
char: Enclosed in single quotes (e.g.,'a','Z','💖').
- Integers: Whole numbers. Rust provides signed (can be negative) and unsigned (non-negative) integers of various sizes:
- Compound Types: Group multiple values into one type.
- Tuples: A fixed-size collection of values, where each value can have a different type.
- Arrays: A fixed-size collection of values, where each value must have the same type.
- String Types: Represent text.
&str: String slice (we’ll discuss this in detail in the next section).String: Growable string.
Variable Declarations:
- We use the
letkeyword to declare a variable. - By default, variables in Rust are immutable (their values cannot be changed after they are initialized).
- To make a variable mutable, we use the
mutkeyword.
4. Live Coding Demonstration:
fn main() {
// Integers
let x: i32 = -10; // Explicit type annotation (i32)
let y = 20; // Type inference (i32 by default)
let z: u8 = 255; // Unsigned 8-bit integer
// Floating-point numbers
let a = 2.5; // Type inference (f64 by default)
let b: f32 = 3.14; // Explicit type annotation (f32)
// Booleans
let is_active = true;
let is_finished: bool = false;
// Characters
let letter = 'A';
let emoji: char = '🚀';
// Tuples
let tup: (i32, f64, char) = (-5, 4.2, 'Z');
let (t1, t2, t3) = tup; // Destructuring a tuple
println!("Tuple values: {}, {}, {}", t1, t2, t3);
println!("Tuple.0 values: {}, Tuple.1 values: {}, Tuple.2 values: {} ", tup.0,tup.1,tup.2);
// Arrays
let arr: [i32; 5] = [1, 2, 3, 4, 5]; // Array of 5 i32 integers
let first = arr[0]; // Accessing an element by index (0-based)
println!("Array values: {}, {}, {}, {}, {}", arr[0],arr[1],arr[2],arr[3],arr[4]);
// Mutability
let mut count = 0; // Mutable variable
count = count + 1;
println!("Count values: {}",count);
// Shadowing
let my_variable = 5;
let my_variable = my_variable + 3; // Re-declaring with a new value
let my_variable = "Now it is String"; // Re-declaring with a String
println!("Shadowing values: {}",my_variable);
}
Key takeaways from the code:
- Type Annotations: We can explicitly specify the type using a colon
:followed by the type name (e.g.,let x: i32 = -10;). - Type Inference: If we don’t provide a type annotation, Rust tries to infer the type based on the value (e.g.,
let y = 20;infersi32). - Mutability:
let mut count = 0;creates a mutable variable that we can change later. - Tuple Access: We can access tuple elements by their index, starting from 0 (e.g.,
tup.0,tup.1). We can also destructure a tuple to assign its elements to individual variables. - Array Access: Arrays are also accessed using 0-based indexing (e.g.,
arr[0]). - Array Declaration: The type of array show with
[i32; 5], first part is type of element and after semicolon fixed size. - Shadowing: Shadowing lets you reuse a variable name within the same scope.
5. Tasks
- Experiment with Types: Create variables of different integer types (
i8,u16,i64, etc.) and assign them values near the boundaries of their ranges (e.g., the maximum value foru8is 255). See what happens if you try to assign a value that is too large or too small for the type. - Tuple Manipulation: Create a tuple containing a string, a boolean, and a floating-point number. Then, access and print each element of the tuple individually.
- Array Practice: Declare an array of
f64values with a length of 3. Initialize it with some floating-point numbers. Then, write code to calculate and print the sum of the elements in the array. - Mutability Challenge: Declare a mutable variable. Perform several arithmetic operations on it (add, subtract, multiply), and print its value after each operation.
- Shadowing Challenge: Declare a immutable variable with number type. Then Shadowing this variable and give string type.