Rust Programming Language - A Comprehensive Guide PDF

Document Details

UnmatchedJadeite2405

Uploaded by UnmatchedJadeite2405

Tags

Rust Programming Programming Languages Computer Science Software Development

Summary

This document provides a basic introduction to the Rust programming language, a strongly-typed language focused on speed and safety. It explains concepts such as memory management, variable declarations, and how to print output in Rust. It also briefly touches on different data types supported by Rust.

Full Transcript

# Why Use Rust? - Rust is a strongly typed programming language that prioritizes speed and safety. - Rust offers safe concurrency & memory management. - Rust tackles two long-standing concerns for C/C++ developers: - memory errors - concurrent programming. - Rust manages memory internally,...

# Why Use Rust? - Rust is a strongly typed programming language that prioritizes speed and safety. - Rust offers safe concurrency & memory management. - Rust tackles two long-standing concerns for C/C++ developers: - memory errors - concurrent programming. - Rust manages memory internally, so trash collection is not required. - In Rust, each reference has a lifespan, which specifies the scope for which that reference is valid. - Over the last 12 years, memory safety concerns have accounted for over 70% of all security flaws in Microsoft products. # The Stack & The Heap - **Stack:** All data stored on the stack must have a known fixed size at compile time. Data is stored in a FIFO (First In, First Out) manner. - **Heap:** Data without a known size at compile time, or data with a size that may change, will be stored on the heap. Data is stored in no particular order. - Rust stores variables on either its stack or its heap. - The behavior (speed, size, etc.) is different between the two options. # "Hello World" In Rust The Rust Hello World program looks like this: ```rust fn main() { println!("Hello, world!"); } ``` # Rust Interpolation - **Interpolation:** The insertion of something of a different nature into something else. - In Rust, you can interpolate other values in what you are printing out. **Example:** ```rust fn main() { println!("My name is {}", "Michael"); } ``` # Variable Naming Syntax - When declaring a variable in Rust, the data type is optional. - The value assigned to the variable determines the data type. - The syntax for defining variables is as follows: - `let variable_name = value;` // no type-specified - `let variable_name:dataType = value;` // type-specified **Example:** ```rust fn main() { let fees = 35000; let salary: f64 = 45000.00; println!("fees is {} and salary is {}", fees, salary); } ``` # Rust Scalar Types - A scalar type is a value that has just one value. **Examples:** - 10, 3.14, 'c' - Rust has four distinct scalar types: 1. **Integer** 2. **Floating point** 3. **Booleans** 4. **Characters** # Unit - Rust has a special type for when a variable does not have a value. - This type is called **unit** and is written in Rust as a pair of parentheses: `()`. - `()` represents both the type and the value of unit. **Example:** ```rust fn main() { let x: () = (); let y: () = println!("Hello, world!"); assert_eq!(x, y); println!("All units are the same!"); } ``` - `()` is a unit literal, which can be placed on the right-hand side of the equal sign to define a variable. - To explicitly define a variable of type unit, you can use `: ()`. # Mutable - By default, variables in Rust are immutable. - To make a variable changeable, prefix it with the term `mut`. - A mutable variable's value can be changed. - The syntax for defining a mutable variable is: - `let mut variable_name = value;` - `let mut variable_name:dataType = value;` **Example:** ```rust fn main() { let mut fees: i32 = 35_000; println!("fees is {}", fees); fees = 45_000; println!("fees changed {}", fees); } ``` # Math In Rust - `+`: addition - `-`: subtraction - `*`: multiplication - `/`: division - `%`: Modulus/Remainder - `(5.0/3.0).floor()`: floor division - `i32::pow(self, exp)`: raise self to exp (u32) and return an integer (i32). - `f32::powi(self, exp)`: raise self to exp (i32) and return a float (f32) - `f32::powf(self, exp)`: raise self to exp (f32) and return a float (f32) # Integers In Rust - In Rust, the way we talk about the types of integers is `i8` (for signed 8-bit integer), `u32` (for unsigned 32-bit integer), etc. - You can use 8, 16, 32, and 64-bit integers. - There's also support for 128-bit integers, but it's rarely needed. - Rust also has special `isize` and `usize` types, which mean "use whatever size the computer I'm on likes." These are usually 64-bit. | Sr. No. | Size | Signed | Unsigned | | ------- | ------- | -------- | ---------- | | 1 | 8 bit | `i8` | `u8` | | 2 | 16 bit | `i16` | `u16` | | 3 | 32 bit | `i32` | `u32` | | 4 | 64 bit | `i64` | `u64` | | 5 | 128 bit | `i128` | `u128` | | 6 | Arch | `isize` | `usize` | # Printing Floats - Just like in C, float (and integer) variables can be formatted as they are being printed. - You have control over the size of the number's display window and the number of digits after the decimal point. - It is not possible to have a comma printed after every three characters. **Example:** ```rust println!("The value is {0:12.2}", 707.126456789); ``` # Attributes - Code like `#[derive(Debug)]` at the beginning of a Rust program is called an **attribute**. - These attributes are small pieces of code that give information to the compiler. - Attributes are not easy to create, but they're simple to use. - If you write an attribute with just `#`, it will affect the code on the next line. - But if you write it with `#!`, it will affect everything in its own space. **Common Attributes:** - `#[allow(dead_code)]` - `#[allow(unused_variables)]` - `#[allow(non_snake_case)]` - If you write code that you don't use, Rust will compile it, but it will let you know. # Blocks - Blocks in Rust are expressions that evaluate to a value. - You can put complex expressions within a block. **Example:** ```rust fn main() { let x: i32 = { 4 + 5 }; println!("4 + 5 == {}", x); } ``` - In this example, `x` will hold the value `9` since the block evaluates the expression `4+5` within it. # Shadowing - In Rust, you can declare variables with the same name. - The new variable will take precedence over the prior variable. This is called **shadowing**. - Constants cannot be shadowed. **Example:** ```rust fn main() { let salary = 110.00; let salary = 2.50; println!("Value of salary: {}", salary); } ``` - The output will be `Value of salary: 2.5` because the second `salary` variable shadows the first one. # String And Str - Rust has two types for strings: `String` and `&str`. - `&str` is called a "string slice." - The difference between `String` and `&str` comes down to ownership and memory. - `String` allocates memory on the heap (the dynamic memory pool), and `&str` does not. It's a reference to a specific section of memory that holds strings. - When to use each type: - Prefer `&str` as a function parameter or if you want a read-only view of a string. - Use `String` when you want to own and mutate a string. # String Types In Rust - In Rust, every value has a type, which tells you what kind of thing it is. - String literals, enclosed in double quotes (e.g., "Hello, world!"), have the type `&str`. **Example:** ```rust fn main() { let name: &str = "Michael"; println!("My name is {}", name); } ``` # Creating Strings - You can create an empty string using `String::new()`. **Example:** ```rust let hello = String::new(); ``` - You can create a `String` from a literal string with `String::from()`. **Example:** ```rust let hello = String::from("Hello, world!"); ``` - The length of a `String` is determined using the `.len()` method. **Example:** ```rust println!("String length = {}", hello.len()); ``` - `String` is the dynamic heap string type. This means it's mutable (can be changed). It's used when you need to own or modify string data. - `&str` is an immutable sequence of UTF-8 bytes somewhere in memory. - You can append a `char` to a `String` using the `push()` method. **Example:** ```rust let mut hello = String::from("Hello, "); hello.push('w'); ``` - You can append a `&str` to a `String` using the `push_str()` method. **Example:** ```rust let mut hello = String::from("Hello, "); hello.push_str("orld!"); ``` # Tuples In Rust - A tuple is a fixed-size collection of values. - There are two ways to create tuples: **Syntax 1:** ```rust let tuple_names: (data_type1, data_type2, data_type3) = (value1, value2, value3); ``` **Syntax 2:** ```rust let tuple_names = (value1, value2, value3); ``` **Example:** ```rust fn main() { let tuples: (i32, f64, u8) = (-326, 4.8, 23); println!("{:?}", tuples); } ``` - You cannot print all the values of a tuple using `println!("{}", tuple)`. This is because a tuple is a compound type. - To print the values in a tuple, use the `println!("{:?}", tuple_name)` syntax. # `:?` - The `:?` formatting directive in `println!("{:?}", tuple_name)` is used to print the debug representation of the tuple. - `{...}` surrounds formatting directives. - `:` separates the name of the thing being formatted from the formatting options. - `?` triggers the use of the `std::fmt::Debug` implementation of the type being formatted. - `fmt::Display` implementations represent types as UTF-8 strings. - `fmt::Debug` implementations are intended for debugging. They represent the internal state of a type as faithfully as possible. # Tuple Type - A tuple is considered a single compound element. - You can extract individual values from a tuple using **pattern matching**. This is called **destructuring**. **Example:** ```rust fn main() { let tup = (600, 7.4, 2); let (a, b, c) = tup; println!("The value of b is: {}", b); } ``` # Changing Tuples - By default, tuples are immutable. - To make a tuple mutable, use the `mut` keyword. **Example:** ```rust let mut tuples: (i32, f64, u8) = (-326, 4.8, 23); tuples.0 = 100; ``` # Conditionals - You can use complex expressions in your `if` condition. **Example:** ```rust fn main() { let temp = 20; if temp > 15 && temp < 27 { println!("It's fairly comfortable in here!"); } } ``` - The body of an `if` expression is a block. You can include multiple statements in this block. **Example:** ```rust fn main() { let temp = 20; if temp > 15 && temp < 27 { println!("It's fairly comfortable in here!"); println!("Would you like a drink?"); } } ``` # Evaluating To Values - By default, `if` expressions evaluate to unit (`()`). - You can make an `if` expression evaluate to a different value, but you must follow these restrictions: 1. There must be an `else` at the end. 2. Each block (for `if`, `else`, `else if`) must evaluate to the same type. **Example:** ```rust fn tell_temperature(temp: i32) { let message = if temp <= 10 { "It's cold!" } else if temp <= 25 { "It's nice!" } else if temp <= 30 { "It's warm!" } else { "It's hot!" }; } ``` # Using An `if` Statement Within A `let` Statement - You can use an `if` statement on the right-hand side of a `let` statement to assign a value to a variable. - The value of the `if` expression will be assigned to the variable. **Example:** ```rust fn main() { let x = if false { 10 } else { 5 }; println!("value of x is: {}", x); } ``` # Match Example - `match` is a powerful control flow construct in Rust. - It compares a value against various patterns. - If a pattern matches, the corresponding code block is executed. **Example:** ```rust fn main() { let state_code = "FL"; let state = match state_code { "NJ" => "New Jersey", "FL" => "Florida", "NY" => "New York", "GA" => "Georgia", _ => "Unknown" }; println!("State name: {}", state); } ``` - This example compares `state_code` to different values and assigns a corresponding state name to the `state` variable. - The `_` pattern is a wildcard. It matches any value that doesn't match the other patterns. # Array Declaration and Initialization - An array is a fixed-size collection of elements of the same type. - You can use three different syntaxes to define and initialize an array in Rust. **Syntax 1:** ```rust let variable_names = [value1, value2, value3]; ``` **Syntax 2:** ```rust let variable_names: [dataType; size] = [value1, value2, value3]; ``` **Syntax 3:** ```rust let variable_names: [dataType; size] = [default_value_for_elements; size]; ``` - The type of the array is inferred from the data type of the first element in the first syntax. # Invalid Array Element Access - If you try to access an array element that is past the array's end, it will cause a runtime error (panic) and your program will crash. **Example:** ```rust fn main() { let x = [11, 22, 33, 44, 55]; println!("{}", x[5]); } ``` - In this example, accessing `x[5]` is invalid because the array `x` has a length of `5`, and the valid indices are `0` to `4`. # Vectors - A vector is a resizable array. - Vectors can grow or shrink in size dynamically. - When a vector reaches its capacity, it will automatically allocate more memory to accommodate new elements. **Creating Vectors** - You can create a new, empty vector using `Vec::new()`. **Example:** ```rust let v: Vec<i32> = Vec::new(); ``` - You can create a vector with a certain initial capacity using `Vec::with_capacity()`. This can improve performance if you know how many elements you'll need to add, as it avoids unnecessary memory reallocations. **Example:** ```rust let v = Vec::with_capacity(10); ``` - You can use the `vec!` macro to create a vector with initial values. **Example:** ```rust let mut v = vec![2, 3, 5, 7]; ``` - You can access elements of a vector using indexing. **Example:** ```rust println!("v[0] = {}", v[0]); ``` - You can add elements to a vector using the `push()` method. **Example:** ```rust v.push(11); ``` # Exit from Loops - You can exit a loop early using the `break` keyword. - If you don't use `break`, a loop will run indefinitely. **Example:** ```rust fn main() { let mut x = 1; loop { println!("Hello everyone!"); if x == 7 { break; } x += 1; } } ```

Use Quizgecko on...
Browser
Browser