The self-learning article series on Rust has now reached the Iterators article, almost covering the basic knowledge of Rust, after which comes advanced knowledge such as smart pointers, async/await, channels, and much more. But I must honestly say to the readers that in the end, the knowledge retained in my head is quite minimal. If you have been following the article series about the self-learning process of Rust, most of what you see is theory recorded according to the original article at...
In JavaScript, besides using loops like `for` to iterate through an array, there are many ways to do the same thing. For example, iterating through an array of numbers. These are methods implemented for iterable data types. In Rust, we also have a similar concept: Iterator. The Iterator is responsible for the logic of iterating through each item and determining when the sequence ends, helping programmers not to have to re-implement this logic. Iterators in Rust are created by calling methods like `iter()` on data structures like `Vec`, and they are lazy, meaning they do not execute until consumed by methods like `sum` or `collect`. All Iterators implement the `Iterator` trait, with the `next` method to iterate through each element while changing the state of the Iterator. Iterators can return immutable references (`iter`), ownership (`into_iter`), or mutable references (`iter_mut`). There are two types of functions using Iterators: consuming adapters like `sum` and non-consuming adapters like `map`, `filter`, which create new Iterators and require a consuming function to collect the results. Using closures in adapters like `map` and `filter` allows customization of behavior on the elements. In terms of performance, Iterators in Rust incur no additional runtime cost thanks to zero-cost abstraction, making them equivalent to `for` loops in performance but clearer and easier to understand, allowing programmers to focus on higher-level goals rather than loop details.
In JavaScript, a Closure refers to a function that can remember and access variables from its outer scope, even after that outer scope has finished executing. In short, when a function is defined inside another function and accesses variables from the parent function, a closure is created. In Rust, closures are similar to those in JavaScript; they can remember and use variables from the outer scope where they are defined. However, closures in Rust are much more complex than in JavaScript...
A year ago, I declared that I would learn Rust within a month. And the result is that the series of articles about the Rust learning process has not ended yet. Can this be considered a failure? I think not. Programming languages are just tools to solve problems. Learning a new one can broaden our experience and help us solve problems more efficiently...
JavaScript is one of the languages that do not need to declare the type. The data type is automatically implied and can change flexibly. A variable initially assigned a value as a number, just after a few lines of code it can become a string or any other value. That's interesting and sometimes a disaster! In Rust, as well as in many typed programming languages, we are forced to declare the type for almost everything like variables, functions... In short, the data type is mandatory and you cannot change from one type to another like in JavaScript.
Error handling is an essential step that cannot be overlooked in programming. The quality of a program heavily depends on this aspect. When a feature is correctly handled for errors, it can help programmers mitigate many risks later on. An error can occur due to various reasons, both objective and subjective. Errors can arise from programmers unintentionally overlooking cases, typographical errors, unforeseen logical overlaps, as well as hardware, software, and network connection errors... This is to illustrate that errors are always waiting for the opportunity to emerge immediately.
So it has been one month, or more like 5-6 days since I started writing my own self-study series on Rust. As stated from the beginning, it was meant to be a "commitment" to learning and also a way to summarize what I have learned, share it, and hopefully receive feedback to point out any mistakes I have made. At the end of the month, the progress we have made is not even half of the set goal. Honestly, with limited time, reading has been challenging, and writing even more so, not to mention the time allocated for other tasks. Actually, I don't want to blame the circumstances, as I was aware of this from the beginning...
Enums, a well-known data structure that allows defining a type by listing its possible variants. Enums have different syntax and usage in each programming language. In Rust, enums are used quite frequently due to the many benefits they offer. In today's article, we will explore enums in Rust and see what makes them special compared to other languages...
In every programming language, there is something equally important - the package manager. Take JavaScript for example, it is already familiar with npm - a tool that allows you to download and share many useful libraries. Here, developers contribute and use packages to accelerate the product development process. In Rust, cargo is a tool that functions similarly to npm, it also allows sharing and downloading packages, but the usage is somewhat different. Therefore, in today's article, we will explore the basic components, modules, and the cargo package manager together.
In the previous article, we learned about the concept of ownership in Rust. Thanks to ownership, Rust knows when a variable is no longer in use and can free up memory. By using & before the variable name, we declare to Rust that we're just "borrowing" the value temporarily without transferring ownership, so the borrowed variable still exists after borrowing, but with some limitations. Today's article will delve into how Rust deals with data borrowing behavior and how it prevents "non-standard" behaviors with borrowed and mutable data during compile time, not runtime...