Rust is a powerful and modern systems programming language known for its memory safety, concurrency, and performance. It's designed to be safe and fast, and it offers a lot of control over low-level details without compromising on safety.
Here's a structured plan to help you get started with Rust:
Rust’s Core Features:
Hello, World!
fn main() {
println!("Hello, world!");
}
fn main(): The entry point of a Rust program.println!(): A macro that prints text to the console.fn main() {
let x = 5; // Immutable by default
let mut y = 10; // Mutable variable
println!("x: {}, y: {}", x, y);
y = 20;
println!("y is now: {}", y);
}
let: Defines a variable.mut: Allows the variable to be mutable.Rust is statically typed. Common types include:
i8, i16, i32, i64, i128, u8, u16, u32, u64, u128f32, f64boolcharExample:
fn main() {
let integer: i32 = 10;
let float: f64 = 3.14;
let boolean: bool = true;
let character: char = 'R';
let tuple: (i32, f64, char) = (500, 6.4, 'z');
let array: [i32; 3] = [1, 2, 3];
println!("integer: {}", integer);
println!("float: {}", float);
println!("boolean: {}", boolean);
println!("character: {}", character);
// Accessing tuple elements
println!("tuple first element: {}", tuple.0);
// Accessing array elements
println!("array second element: {}", array[1]);
}
fn main() {
let sum = add(5, 3);
println!("Sum is: {}", sum);
}
fn add(a: i32, b: i32) -> i32 {
a + b // No semicolon means this is the return value
}
fn: Defines a function.->): Specifies the return type.fn main() {
let number = 7;
if number < 5 {
println!("Less than 5");
} else if number == 5 {
println!("Equal to 5");
} else {
println!("Greater than 5");
}
// Using if in a let statement
let condition = true;
let number = if condition { 5 } else { 6 };
println!("Number is: {}", number);
}
loop: Infinite loop.while: Loop with a condition.for: Iterating over a range or collection.fn main() {
// Loop
let mut count = 0;
loop {
count += 1;
if count == 3 {
break; // Exits the loop
}
}
// While loop
while count < 5 {
println!("Count: {}", count);
count += 1;
}
// For loop
for number in 1..4 {
println!("Number: {}", number);
}
}
Rust’s ownership model is one of its unique features, ensuring memory safety without needing a garbage collector.
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 is now invalid, s2 owns the String
println!("{}", s2);
}
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // Borrowing s1
println!("Length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize { // s is a reference to a String
s.len() // len() returns the length of the String
} // s goes out of scope but doesn't drop the String
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s);
}
fn change(s: &mut String) {
s.push_str(", world");
}
Lifetimes ensure that references are valid as long as they need to be. The syntax can be tricky at first, but it's crucial for understanding how Rust manages memory.
fn main() {
let string1 = String::from("abcd");
let string2 = String::from("xyz");
let result = longest(&string1, &string2);
println!("The longest string is {}", result);
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
sign_in_count: 1,
active: true,
};
println!("Username: {}", user1.username);
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::Move { x: 10, y: 20 };
match msg {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Text: {}", text),
Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b),
}
}
Pattern matching with match is a powerful feature in Rust.
fn main() {
let number = 6;
match number {
1 => println!("One"),
2 => println!("Two"),
3 => println!("Three"),
4 | 5 | 6 => println!("Four, five, or six"),
_ => println!("Other"),
}
}
Modules help organize code by grouping related functions, structs, etc.
mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
}
fn main() {
let sum = math::add(5, 3);
println!("Sum is: {}", sum);
}
Crates are packages of Rust code. You can include external crates in your project using Cargo, Rust’s package manager.
Add this to your Cargo.toml to include an external crate:
[dependencies]
rand = "0.8.4"
Rust provides safe abstractions for concurrency, avoiding common issues like data races.
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap(); // Wait for the spawned thread to finish
}
Rust has a robust error-handling model that distinguishes between recoverable and unrecoverable errors. It uses two main types:
Result<T, E> Enum:This is used for recoverable errors and is similar to Option, but it can
contain an error value.
Ok(T) signifies a successful operation.Err(E) signifies an error.Example:
use std::fs::File;
use std::io::{self, Read};
fn read_file() -> Result<String, io::Error> {
let mut file = File::open("hello.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn main() {
match read_file() {
Ok(contents) => println!("File contents: {}", contents),
Err(e) => println!("Failed to read the file: {}", e),
}
}
? Operator: Propagates errors, returning them from the function if they occur.panic! Macro:This is used for unrecoverable errors and will stop the program.
Example:
fn main() {
let v = vec![1, 2, 3];
v[99]; // This will cause a panic!
}
Rust’s generics allow you to write flexible, reusable code. Traits define shared behavior that types can implement.
Generics let you write code that can work with any data type.
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
println!("The largest number is {}", largest(&number_list));
}
Traits define shared behavior that can be implemented for various types.
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct Post {
pub title: String,
pub author: String,
}
impl Summary for Post {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
fn main() {
let post = Post {
title: String::from("Rust Programming"),
author: String::from("John Doe"),
};
println!("Post Summary: {}", post.summarize());
}
Rust provides smart pointers, such as Box, Rc, and RefCell, to manage
memory dynamically and safely.
Box<T>Box is used to allocate values on the heap rather than the stack.
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
Rc<T>Rc (Reference Counted) enables multiple ownership of data.
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = Rc::clone(&a);
println!("a = {}, b = {}", a, b);
}
RefCell<T>RefCell enables mutable borrowing at runtime, enforcing borrowing rules at
runtime rather than compile-time.
use std::cell::RefCell;
fn main() {
let x = RefCell::new(42);
*x.borrow_mut() += 1;
println!("x = {}", x.borrow());
}
Rust provides several common collections like vectors, strings, and hash maps that are essential for data handling.
Vectors are resizable arrays.
fn main() {
let mut v = vec![1, 2, 3];
v.push(4);
println!("{:?}", v);
}
Strings are a collection of UTF-8 encoded text.
fn main() {
let s = String::from("Hello, Rust!");
println!("{}", s);
}
Hash maps store key-value pairs.
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Red"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name).unwrap_or(&0);
println!("Score of {}: {}", team_name, score);
}
Macros are a way to write code that writes other code (metaprogramming). Rust
provides a few types of macros, such as declarative macros (macro_rules!) and
procedural macros.
Declarative macros are defined using macro_rules!.
macro_rules! say_hello {
() => {
println!("Hello!");
};
}
fn main() {
say_hello!();
}
Rust is a powerful language with many advanced features. This introduction covers the basics, but as you delve deeper, you'll discover more about its ownership model, concurrency, and performance optimizations. The best way to learn Rust is to write Rust, so I encourage you to start coding with small projects and gradually tackle more complex tasks as you get comfortable with the language. The official Rust book, "The Rust Programming Language", is an excellent resource for further learning.
Happy coding!
provided by chat-gpt