Rust is static types language Rustc compiler convert rust to executable cargo rust build system and pkg manager
cargo new projectname (like npm in js)
- cargo.tomo → (similar to pkg.json file in js)
fn main(){
println!("hello world")
println!("{}",1) // we cannot directly print number we need to format
}
cargo run filename → compile to bin and run rustc filename →convert to bin and we need to run
Varaibles
- are imutable by default
- const my need to define the vairable types
let x =1
x=5 // will error
let x= 5; //no error we can redeclare to bypasss
//we also cannot chnage the type
let a =1
a="hai" ///error
let a ="hai" //allowed
//const must need to define the type
const A : u32 = 50;
Types
Data type of every expression must be known at compile time.we don’t need to explicitly specify the type of every variable, but the type system will infer the types based on how the variables are used. This is known as type inference.
Scalar Types
- Integers:
i32
: 32-bit signed integer (default)i64
: 64-bit signed integeru32
: 32-bit unsigned integeru64
: 64-bit unsigned integerisize
: Pointer-sized signed integerusize
: Pointer-sized unsigned integer
- Floats:
f32
: 32-bit floating-point numberf64
: 64-bit floating-point number (default)
- Characters:
char
: Unicode scalar value (e.g., ‘a’, ’😊’)
Example: let x: char = 'a';
- Boolean:
bool
: true or false
Example: let x: bool = true;
Compound Types
fn main() {
//Array
// 1. Creating an array
let numbers = [1, 2, 3, 4, 5];
println!("Array: {:?}", numbers);
// 2. Accessing an array element
println!("First element: {}", numbers[0]);
// 3. Array length
println!("Array length: {}", numbers.len());
// 4. Array iteration
for num in &numbers {
println!("Number: {}", num);
}
// 5. Array mutation
let mut numbers_mut = [1, 2, 3, 4, 5];
numbers_mut[0] = 10;
println!("Mutated array: {:?}", numbers_mut);
// 6. Creating an array with a default value
let mut bools = [false; 5];
println!("Array of booleans: {:?}", bools);
// 7. Array slicing
let slice = &numbers[1..4];
println!("Slice: {:?}", slice);
// 8. Multidimensional arrays
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
println!("Matrix: {:?}", matrix);
// 1. Creating a tuple
let person = ("John", 30, "Developer");
println!("Name: {}, Age: {}, Occupation: {}", person.0, person.1, person.2);
// 2. Pattern matching with tuples
let (name, age, occupation) = person;
println!("Name: {}, Age: {}, Occupation: {}", name, age, occupation);
// 3. Tuple indexing
println!("Name: {}", person.0);
println!("Age: {}", person.1);
println!("Occupation: {}", person.2);
// 4. Tuple destructuring
let (_, age, _) = person;
println!("Age: {}", age);
// 5. Creating a tuple with different types
let mixed_tuple = (1, "hello", true, 3.14);
println!("{:?}", mixed_tuple);
// 6. Tuple as function return value
let result = calculate_area(10, 20);
println!("Area: {}", result.0);
println!("Perimeter: {}", result.1);
}
fn calculate_area(length: i32, width: i32) -> (i32, i32) {
let area = length * width;
let perimeter = 2 * (length + width);
(area, perimeter)
}
- Structs:
- A custom data type with named fields Example
struct Person {
name: String,
age: u32,
}
let x: Person = Person {
name: "Alice".to_string(),
age: 30,
};
- String : have two imutable fixed length and growable heap allocated data structure
fn main() {
let s = "hello"
//growable string
let mut s = " Hello, World! ".to_string();
// Trim whitespace from the beginning and end of the string
s = s.trim().to_string();
// Convert the string to uppercase
s = s.to_uppercase();
// Replace commas with dashes
s = s.replace(",", "-");
// Insert a substring at a specific position
s.insert_str(7, " Beautiful ");
// Remove a range of characters from the string
s.remove(15..20);
println!("{}", s); // Output: "HELLO- Beautiful WORLD!"
}
Loops
fn main() {
// 1. For loop
let numbers = [1, 2, 3, 4, 5];
for num in numbers {
println!("For loop: {}", num);
}
// 2. While loop
let mut i = 0;
while i < 5 {
println!("While loop: {}", i);
i += 1;
}
// 3. Loop (infinite loop)
let mut j = 0;
loop {
println!("Loop: {}", j);
j += 1;
if j == 5 {
break;
}
}
// 4. For loop with iterator
let fruits = vec!["apple", "banana", "cherry"];
for fruit in fruits {
println!("For loop with iterator: {}", fruit);
}
// 5. For loop with range
for k in 1..6 {
println!("For loop with range: {}", k);
}
}
Macro
In Rust, a macro is a way to extend the language itself. Macros are essentially functions that generate code at compile-time, allowing you to create new syntax, abstractions, and domain-specific languages (DSLs) within Rust.
Macros are defined using the macro
keyword, followed by the name of the macro and a set of rules that define how the macro should be expanded. When the macro is invoked, the Rust compiler will replace the macro invocation with the expanded code.
Macros need to be call with !
macro_rules! greet {
($name:expr) => {
println!("Hello, {}!", $name);
};
}
fn main() {
greet!("Alice");
greet!("Bob");
}
Types of Macros in Rust:
- Declarative Macros: These macros are defined using the
macro_rules!
syntax and are used to generate code at compile-time. - Procedural Macros: These macros are defined using the
proc_macro
attribute and are used to generate code at compile-time using a procedural interface. - Attribute Macros: These macros are used to attach attributes to items, such as functions or structs.
Builtin Macro
1. println!
: Prints its arguments to the standard output, followed by a newline character.
2. vec!
: Creates a new vector with the specified elements.
3. format!
: Formats its arguments into a string.
4. assert!
: Asserts that a condition is true, and panics if it’s false.
5. assert_eq!
: Asserts that two values are equal, and panics if they’re not.
6. assert_ne!
: Asserts that two values are not equal, and panics if they are.
7. panic!
: Panics with a custom message.
8. unimplemented!
: Panics with a message indicating that a function or method is not implemented.
9. todo!
: Panics with a message indicating that a function or method is not implemented, and suggests that it should be implemented.
10. include!
: Includes the contents of a file into the current module.
11. include_str!
: Includes the contents of a file as a string.
12. module!
: Defines a new module.
13. concat!
: Concatenates its arguments into a single string.
14. stringify!
: Converts its argument into a string.
15. debug_assert!
: Asserts that a condition is true, and panics if it’s false, but only in debug builds.
Function
fn main() {
// 1. Defining a function
fn greet(name: &str) {
println!("Hello, {}!", name);
}
greet("Alice");
// 2. Defining a function with return value
fn add(a: i32, b: i32) -> i32 {
a + b
}
let result = add(2, 3);
println!("Result: {}", result);
// 3. Defining a closure
let names = vec!["Alice", "Bob", "Charlie"];
let greet = |name: &str| println!("Hello, {}!", name);
for name in names {
greet(name);
}
// 4. Defining a closure with capture
let message = "Hello, ".to_string();
let greet = move |name: &str| println!("{}", format!("{}{}", message, name));
greet("Alice");
// 5. Defining a closure as a function parameter
fn process<F>(data: &str, func: F)
where
F: Fn(&str),
{
func(data);
}
process("Hello, World!", |s| println!("{}", s));
// 6. Defining a closure as a function return value
fn create_greeter(name: &str) -> impl Fn() {
move || println!("Hello, {}!", name)
}
let greeter = create_greeter("Alice");
greeter();
}