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
  • For a long time, I have been thinking about how to increase brand presence, as well as users for the blog. After much contemplation, it seems the only way is to share on social media or hope they seek it out, until...

    Wearing this shirt means no more worries about traffic jams, the more crowded it gets, the more fun it is because hundreds of eyes are watching 🤓

    (It really works, you know 🤭)

    » Read more
  • A cycle of developing many projects is quite interesting. Summarized in 3 steps: See something complex -> Simplify it -> Add features until it becomes complex again... -> Back to a new loop.

    Why is that? Let me give you 2 examples to illustrate.

    Markdown was created with the aim of producing a plain text format that is "easy to write, easy to read, and easy to convert into something like HTML." At that time, no one had the patience to sit and write while also adding formatting for how the text displayed on the web. Yet now, people are "stuffing" or creating variations based on markdown to add so many new formats that… they can’t even remember all the syntax.

    React is also an example. Since the time of PHP, there has been a desire to create something that clearly separates the user interface from the core logic processing of applications into two distinct parts for better readability and writing. The result is that UI/UX libraries have developed very robustly, providing excellent user interaction, while the application logic resides on a separate server. The duo of Front-end and Back-end emerged from this, with the indispensable REST API waiter. Yet now, React doesn’t look much different from PHP, leading to Vue, Svelte... all converging back to a single point.

    However, the loop is not bad; on the contrary, this loop is more about evolution than "regression." Sometimes, it creates something good from something old, and people rely on that goodness to continue the loop. In other words, it’s about distilling the essence little by little 😁

    » Read more
  • Alongside the official projects, I occasionally see "side" projects aimed at optimizing or improving the language in some aspects. For example, nature-lang/nature is a project focused on enhancing Go, introducing some changes to make using Go more user-friendly.

    Looking back, it resembles JavaScript quite a bit 😆

    » 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