Adding a low-level memory language to your toolset increase your knowledge about memory management. Good concepts of a new language can often be used in other languages by yourself.
Rust is a quite new language. Graydon Hoare created it as a private project. In that time, he worked at the Mozilla Foundation. They started to sponsor the work on the project in 2009.
In 2015, the first stable release was published.
Now Rust gets a new release every 3 weeks. Breaking changes or new language features (like the async keyword) are introduced via an edition. As of this writing, 2021 is the latest edition.
Beside the edition, their is also the toolchain version you can choose: stable and nightly.
The stable release can be considered as production-ready. Feature of the language that are marked stable, are guaranteed to be supported compared to the nightly build.
Python and Ruby for example are interpreted programming languages. They scan the code and execute it. When data gets out of scope, they are collected via a garbage collector. A garbage collector regularly scans the objects that are created while the application is running and frees them from memory. This process takes time, especially in a application with a lot of objects.
But not only interpreted languages have a garbage collector: java is a very popular languages that use this technology as well even though it is compiled to java byte code (and then executed on the java virtual machine)
Other low level languages like c and c++ give the responsibility to the memory management to the developer. This can lead to bugs and security vulnerabilities. It have the benefit in very high performance.
Rust have a different concept of memory management. Allocations (get memory from the operating system) and de-allocations (free it again) are created at compile time. You have to follow certain rules that the compiler checks. Following this rules guarantees that your program is in general free of memory bugs.
The Rust ecosystem contains of different applications that are installed with rust together. Lets get a quick overview on them:
cargo is handling the compilation and dependency management. Dependencies are written via Cargo.toml files. After initial generation, you can find a Cargo.lock file where your dependencies are defined with the precise version definition. It can be compared to Pipfile.lock in the python world or yarn.lock in the nodejs world.
rustc is the compiles (of course, written in rust) to compile an application. You can call rustc directly, but its preferred to build and execute tests via cargo.
With clippy, to will trigger in depth code analysis and recommendations of your rust program. Its not on by default it the jetbrains tools, but I can highly recommend it to have it running all the time.
After you have installed rust on your operating system, you can create a new project with cargo. Lucky, this will also generate a hello world binary application for us:
cargo new hello-world && cd hello-world
This will create a new directory "hello-world" with following files in it (using tree):
.
├── Cargo.toml
└── src
└── main.rs
Where Cargo.toml is the file for dependency and settings management that I mentioned before. Inside src their is the actual file with the generated source code. Lets have a look at it.
fn main() { println!("Hello, world!"); }
fn stands for function. With main you define a function that should be executed when launching the application. We accept no arguments, but the parentheses are required. To mark a block of code, you need curly brackets.
Commands ending with an exclamation mark are called declarative macros. They get expanded at compile time. In this case, the macros transfers the print statement to the console in a system specific style. You can also cross compile when building for a different operating system.
To compile the application, run cargo build. This will by default build the application in debug mode. With cargo run you build and execute the generated binary in one step. Its placed in target/debug/hello-world.
You can test your code as unit-test or as integration test. Unit tests are placed inside the file where you are creating your implementation. Integration tests are placed inside a tests directory inside your project root. You have only access to public structures in this context.
You want to deep dive more into the language? Feel free to write me a message for more rust related content. I can recommend following resources: