Skip to content

Latest commit

 

History

History
274 lines (186 loc) · 7.04 KB

File metadata and controls

274 lines (186 loc) · 7.04 KB

Rust Programming Language

Rust Programming Language

Notes for learning the rust language using the official book.

Current version is 1.82 version.

Rust Docs it describes the low level stuff.

Rust jargon explanation from ChatGPT

These are “high level” concepts. Not including the low level stuff like heap-allocation or memory stuff.

Variables

A variable in Rust is a way to store a value that can be accessed and manipulated throughout your code. In Rust, variables are immutable by default, meaning once a value is assigned to a variable, you cannot change it unless you explicitly make it mutable.

In short, variable is a “name” of things.

There are 2 types of variable in Rust.

Immutable:

This cannot change.

let x = 5;

Mutable example:

This can change by using `mut`.

let mut x = 5;

Function

A function in Rust is a block of code that can take input (parameters), do something with that input, and possibly return a value.

Code example:

fn greet(name: &str) -> String {
    let greeting = format!("Hello, {}!", name);
    greeting
}

Code explanation:

fn: Keyword used to define a function.

greet: Name of the function.

(name: &str): This is the parameter part, indicating that greet takes a string slice (&str) as input.

-> String: The function will return a String (a heap-allocated string in Rust).

The function returns the greeting message.

A function is kinda like how you “command” a given task or “steps to take.” Take cooking analogy. There are steps to take before actually cooking on fire. Chop the vegetables, mixing flour and water. Then adding salt.

Data Types

Rust Book

Every value in Rust is of a certain data type, which tells Rust what kind of data is being specified so it knows how to work with that data. We’ll look at two data type subsets: scalar and compound.

Rust is a strongly typed language, meaning that everything has to be declared as a “state.” Is it a character, an integer or a float number. Different from other programming language like python.

You have to specify the type of data.

Ownership

One of the key concepts in Rust is ownership, which determines how memory is managed. Rust uses a unique system of ownership to ensure memory safety without a garbage collector.

Ownership rules:

  • Each value in Rust has a variable that owns it.
  • There can only be one owner at a time.
  • When the owner goes out of scope, the value is automatically dropped (memory is freed).
fn main() {
    let s1 = String::from("Hello");  // s1 owns the string
    let s2 = s1;  // Ownership is moved from s1 to s2

    // println!("{}", s1);  // This would cause a compile-time error because s1 no longer owns the string
    println!("{}", s2);  // This works because s2 owns the string now
}

When ownership is transferred (like s1 to s2), s1 is no longer valid.

Borrowing and References

This is what makes Rust unique and safe from a memory standpoint. The borrow-checker.

Rust allows you to borrow data using references. A reference is like a pointer, but it comes with rules that prevent data races and ensure safety.

Immutable example:

let x = 5;
let y = &x;  // y is an immutable reference to x
println!("{}", y);  // This works fine

Mutable example:

let mut x = 5;
let y = &mut x;  // y is a mutable reference to x
*y += 1;         // Dereference y to modify x
println!("{}", x);  // Prints: 6

Struct

Struct definition:

struct Person {
    name: String,
    age: u32,
}

let person = Person {
    name: String::from("Alice"),
    age: 30,
};

You can create instances of a struct and access its fields using dot notation:

println!("{} is {} years old.", person.name, person.age);
  

Enum

An enum is a way to define a type that can be one of several variants. It’s useful for handling a set of related but different possibilities.

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

let move_dir = Direction::Up;

  

Enums are often used with match statements to pattern match on different variants.

Match

The match keyword is Rust’s way of performing pattern matching, which is very powerful and similar to a switch-case statement in other languages, but much more expressive.

let number = 13;
match number {
    1 => println!("One"),
    2..=5 => println!("Between two and five"),
    _ => println!("Something else"),
}
  

Here, `_` is a catch-all pattern.

Concurrency

Rust makes it easier to write safe concurrent code by using its ownership system. Rust provides threads, async/await, and channels for handling concurrent execution without worrying about data races.

use std::thread;

let handle = thread::spawn(|| {
    println!("Hello from a new thread!");
});

handle.join().unwrap();  // Wait for the thread to finish

  

Async/Await: Rust has asynchronous programming built into the language, allowing you to write concurrent code that doesn’t block threads.

Lifetime

Lifetimes are a way of expressing the scope of references in Rust. They are used to prevent dangling references (when you reference memory that is no longer valid).

fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    if s1.len() > s2.len() {
        s1
    } else {
        s2
    }
}
  

The “a` here is a lifetime annotation that ensures that both `s1` and `s2` live at least as long as the returned string.

Error handling

Rust has a unique way of handling errors using the Result and Option types:

  1. Option: Represents a value that could be Some(T) or None (e.g., when a value might not exist).
    let some_value: Option<i32> = Some(42);
    let no_value: Option<i32> = None;
          
  2. Result: Represents either success (Ok(T)) or failure (Err(E)).
    fn divide(x: i32, y: i32) -> Result<i32, String> {
      if y == 0 {
          Err(String::from("Cannot divide by zero"))
      } else {
          Ok(x / y)
      }
    }
    
          

You can use match or the ? operator to handle these types.

Summary

These are just some of the key terms and concepts you’ll encounter while learning Rust. The language has a steep learning curve, but its features—like ownership, borrowing, and concurrency—make it powerful and safe for systems-level programming. As you go deeper, you’ll encounter more advanced topics like generics, macros, and the extensive Rust ecosystem for building web servers, applications, and tools.