1 Month Learning Rust - The Fundamentals of the Rust Programming Language

1 Month Learning Rust - The Fundamentals of the Rust Programming Language

Daily short news for you
  • swapy is a library that helps you create drag-and-drop actions to easily swap the positions of components.

    The library supports a wide range of platforms, making it perfect for building something personalized like a user’s Dashboard.

    » Read more
  • After waking up, I saw the news feed flooded with articles about Microsoft rewriting the TypeScript compiler - tsc in Go, achieving performance that is 10 times faster than the current one. Wow!

    But when I saw this news, the question immediately popped into my head: "Why not Rust?" You know, the trend of rewriting everything in Rust is hotter than ever, and it’s not an exaggeration to say that it's sweeping through the rankings of previous legacy tools.

    What’s even more interesting is the choice of Go - which supposedly provides the best performance to date - as they say. Many people expressed disappointment about why it wasn’t C# instead 😆. When something is too famous, everything is scrutinized down to the smallest detail, and not everyone listens to what is said 🥶

    Why Go? #411

    » Read more
  • I read this article Migrating Off Oh-My-Zsh and other recent Yak Shavings - the author essentially states that he has been using Oh-My-Zsh (OMZ) for a long time, but now the game has changed, and there are many more powerful tools that have come out, so he realizes, oh, he doesn't need OMZ as much anymore.

    I also tried to follow along because I find this situation quite similar to the current state. It was surprising to discover something new. I hope to soon write a post about this next migration for my readers 😁

    » Read more

The Challenge

It's a common story: the basics always seem easy to learn until we try to apply them in real-world situations, where numerous issues arise. Why is it that documentation provides only a few simple commands, but when we read a real project, it seems to be full of Martian syntax? @@.

Theory vs. Practice

In reality, documentation should guide us from the fundamentals to advanced topics, rather than introducing complex syntax right away. If we have a solid grasp of fundamental knowledge, we can still write our first program. As we become more accustomed or work on various real-world projects, naturally, getting acquainted with new things becomes faster. Therefore, fundamental knowledge lays a strong foundation for us before we venture into more significant tasks.

Last week, I went through Rust's documentation from start to finish, focusing on syntax and the initial fundamental concepts.

Installation

Rust supports multiple platforms. You can install Rust with a single command if you're using macOS or Linux.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Or, you can explore other installation methods at Other Rust Installation Methods.

Hello World Program

Creating a "Hello, world!" program in Rust is straightforward.

fn main() {
    println!("Hello, world!");
}

println! is a macro, essentially a shorthand for a function. In this case, without using macros, you might have to write longer code. In Rust, you will encounter various macros to expedite code writing. println! functions similarly to console.log in JavaScript; it prints everything to the console screen.

Syntax for "building" the program into a binary:

$ rustc main.rs

You can then run the program using:

$ ./main
Hello, world!

To run a Rust program, you first need to compile it into machine code. Unlike JavaScript, where programs execute immediately without compilation, Rust also offers mechanisms for immediate execution, but I won't delve into that in this article.

Variables, Data Types, and Functions

In Rust, you declare a variable using the let or const keyword.

let a: i32 = 1;
# or let the type be inferred
let a = 1; // a: i32

As Rust is a statically typed language, variables need to be declared with a type when initialized, or Rust will automatically infer the type for the first declaration.

By default, Rust variables are immutable, meaning their values cannot be changed. You use the mut keyword to declare mutable variables.

let mut a: i32 = 1;
a = 2;

Functions in Rust must be value-stable. Rust doesn't allow declaring functions with values that change based on variables.

const A: i32 = 1;
# or
const A: i32 = 1 + 2;

# Computing from a variable will result in an error
const A: i32 = a + 1; // error

Basic data types in Rust include char, string, integer, float, boolean, and data structures like Tuple and Array. For more details, you can refer to Data Types.

Functions in Rust can return data or not. If they return data, you need to declare the return type.

# Function without a return value
fn another_function() {
    println!("Another function.");
}

# Function with a return value
fn five() -> i32 {
    return 5;
}
# Or use a concise format
fn five() -> i32 {
    5
}

# Function with parameters
fn five(n: i32) -> i32 {
    n
}

In Rust, ending a line with ; is mandatory. However, if you don't use return, the line without ; is treated as the return value.

if...else and Loops

In Rust, if...else acts as an expression, meaning it can return a value or not, similar to functions.

# if...else without returning a value
let number = 3;

if number < 5 {
    println!("condition was true");
} else {
    println!("condition was false");
}

# if...else returning a value that can be assigned to a variable
let condition = true;
let number = if condition { 5 } else { 6 };

When a value is returned, there must always be an else, and the return type must be consistent.

Unlike JavaScript, where evaluation expressions can be data or logical operations, Rust mandates that the expression in if must be a logical expression, meaning it must be either true or false.

The basic syntax for looping is to use loop.

let mut counter = 0;

let result = loop {
    counter += 1;

    if counter == 10 {
        break counter * 2;
    }
};

Additionally, Rust has while loops.

let mut number = 3;

while number != 0 {
    println!("{number}!");

    number -= 1;
}

And for loops.

let a = [10, 20, 30, 40, 50];

for element in a {
    println!("the value is: {element}");
}

for can be used with any data type that can be iterated, similar to JavaScript. For example:

for number in (1..4) {
    println!("{number}!");
}

(1..4) is a u32 array structure, so for iterates through each element and executes the statements inside the curly braces.

Structs

Struct is a data structure with attributes and associated methods, similar to a Class in object-oriented programming.

struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}

let user = User {
    active: true,
    username: String::from("hoaitx"),
    email: String::from("[email protected]"),
    sign_in_count: 1,
};

Struct also has a syntax similar to Spread syntax in JavaScript for overriding data.

let user2 = {
    username: String::from("2coffee"),
    email: String::from("[email protected]"),
    ..user
};

To declare methods for a struct, you use impl.

impl User {
    fn sayName(&self) -> String {
        self.username
    }

    fn sayEmail(&self) -> String {
        self.email
    }
}

let user = User {
    active: true,
    username: String::from("hoaitx"),
    email: String::from("[email protected]"),
    sign_in_count: 1,
};

println!("user say name {}", user.sayName);

self is similar to this in classes, used to refer to its attributes and methods.

When methods don't have self, they are called associated functions. They are used to create a predefined instance of the struct.

impl User {
    fn default(size: u32) -> User {
        Self {
            active: false,
            username: String::from(""),
            email: String::from(""),
            sign_in_count: 0,
        }
    }
}

let defaultUser = User::default();

This is reminiscent of the String::from() method.

A Brief Explanation of Memory in Rust

There are many new concepts here. For example, the String::from() syntax for creating a string in Rust. Why is it so complicated? In contrast, in JavaScript or many other languages, you simply put them in single ('') or double ("") quotes. To clarify, we need to familiarize ourselves with stack and heap memory in Rust.

Stack memory is used to store fixed-size variable values, such as char, str, int32, int64, and so on, whereas heap memory, on the contrary, has variable-sized data depending on runtime. Data within double quotes ("") is identified as char Data within double quotes ("") is str, while using String:from() makes it String and stores it in the heap.

So, in summary, what's the difference between str and String? It's primarily in memory management in Rust. Rust lacks automatic garbage collection, so it had to develop memory management for variables, or in other words, the variable's lifetime in the program.

Are all variables immutable by default in Rust? Yes, that means they cannot be changed after declaration. Don't worry; Rust still allows us to declare mutable variables, which is a kind of "102" memory management mechanism. We'll explore this further in the next article!

Premium
Hello

5 profound lessons

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

View all

Subscribe to receive new article notifications

or
* The summary newsletter is sent every 1-2 weeks, cancel anytime.

Comments (1)

Leave a comment...
Avatar
Ẩn danh1 year ago
''Dữ liệu trong dấu nháy kép ("") được xác định là char''. theo mình biết thì char là kiểu dữ liệu 4 bytes và trong rust nó hỗ trợ unicode. Còn char mà bạn nhắc đến trong bài viết được đặt trong "" thì nó là str
Reply
Avatar
Xuân Hoài Tống1 year ago
Cảm ơn bạn đã chỉ ra sai sót, mình đã cập nhật lại bài viết :D