This post published on my blog before
Hi everyone! In this post, I'll talk about Rust programming language.
Introduction
The Rust programming language helps you write faster, more reliable software. High-level ergonomics and low-level control are often at odds in programming language design; Rust challenges that conflict. Through balancing powerful technical capacity and great developer experience, Rust gives you the option to control low-level details (such as memory usage) without all the hassle traditionally associated with such control.
Source: https://doc.rust-lang.org/book/ch00-00-introduction.html#introduction
You can build system software, web applications, etc. If you used any programming language before, the first steps aren't hard to understand what is happening.
In this post, I'll use The Rust Programming Language documentation.
In this chapter, we'll see installation processes, our first program, and cargo
.
Installation
I prefer rustup to install Rust language. Actually, they recommended to rustup. I used it.
We'll go to the Install Rust page: https://www.rust-lang.org/tools/install
You will see installation instructions for your operating system.
You can install Rust on Linux or macOS with this command;
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
You should see this message: Rust is installed now. Great!.
You can add Rust to the system path manually by this way;
source $HOME/.cargo/env
If you're using Windows, you can find Rust's Windows binary file on the installation page.
You can update rustup or uninstall it with these commands;
Update
rustup update
Uninstall
rustup self uninstall
To check Rust installed correctly use this command;
rustc --version
Our First Rust Program
We can write our first program in different ways. The first way is so simple. The first program will be a hello world program in both ways.
First Way
Create a file called main.rs wherever you want.
fn main() {
println!("Hello World!");
}
And run this command;
rustc main.rs
It will create an executable file with the source code's file name. You can run it as an executable file.
./main
Second Way
We can create a project with cargo. This cargo is a package manager for Rust. Yes, you can build your project with cargo.
cargo new hello_world
cd hello_world
In this way, cargo created a project structure for us. Now our project structure is like that;
src/
main.rs
Cargo.toml
cargo
also inits an empty git repository.
You can run your code using this command;
cargo run
This command will run your main.rs file under the src folder. You can also build your project for release.
cargo build --release
You can check your Cargo.toml file. It should look like that;
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Ali GOREN <YOUR_VERY_HIDDEN_EMAIL>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
Let's Review Our First Program
First of all, we'll be review this code piece;
fn main() {
}
So, really what the heck is that?
You define a function with these kinds of lines. If you're familiar with C like programming languages, you will understand what is this. If you don't know what is this, don't worry. I'll explain it.
The main function is a special function in some programming languages. This is an entry point to run your programs. It is always the first code that runs in every executable Rust program.
We didn't pass parameters to this function. If you need to pass parameters, they should be inside parentheses. (params1, params2)
.
The second thing you should know is the curly brackets. These are wraps the function body. For example;
fn main() {
// this is function body
}
There are some advisories to style guide but you shouldn't know that for now.
Let's dig into the function body.
We see this code piece in the body;
println!("Hello World!");
The println!
calls a Rust macro. We'll not compare macros and function in this post. But they're different. For now, you should know !
means that you're calling a macro.
Every string statement needs to be in double-quotes. So, "Hello World!"
is a string statement. It will be printed on the screen.
We added a semi-colon to the end of the println!
. You don't have to do that. This means this expression is over and the next one is ready to begin. Most lines of Rust code end with a semicolon.
That's all. Thanks for reading.
Top comments (8)
Nice overview - you could have mentioned how heavily FP (functional programming) influenced Rust is, that's one of the first things I noticed when studying it.
Rust, in my opinion, is one of the most elegant programming languages - personally I think it's better designed than Go (what I really dislike about Go is the total absence of abstract types or generics, which makes functional style programming virtually impossible, forcing the programmer to do everything procedurally).
Even though it's not a pure FP (Functional Programming) language, it reminded me a LOT of Haskell. Amazing how well Rust's type checking works to ensure safe and "correct" programming.
By the way, what I also noticed is how fantastic Rust's official documentation (the Rust Programming Language tutorial) is - that's really a rare example of official docs that you can read from cover to cover and that makes 3rd party tutorials redundant.
This is a fantastic comment. Really. Btw, I agree with you. I never saw this kind of official documentation.
I also like Nim's documentation.
nim-lang.github.io/Nim/tut1.html
nim-lang.github.io/Nim/tut2.html
nim-lang.github.io/Nim/tut3.html
Nice, I came across Nim sometime ago ... how would you say it compares to Rust? It sort of looks like a cross between Rust, Go and Python - it uses indentation instead of semicolons, it does have a runtime and garbage collector, and so on. Something like combining "best of" features from Go and Rust with Python syntax thrown in :-)
I'm not sure that there's too much of FP in Rust. With all nice abstractions and lambdas, Rust discourages programmers from using by-value arguments, since in move semantic it can only happen once and when borrowing (especially mutably) we're dealing with references and mutate state in place which is be definition procedural.
Not sure if I understand your argument - when you say "when borrowing (especially mutably)" then you already assume that you're using mutable variables, implying that you're using a procedural rather than an FP approach ... that's an option, but not the only way to do things.
When going through Rust's official docs (the programming language tutorial) they seem to emphasize abstract data types and interfaces before they do "OO" constructs - and variables being immutable by default promotes an FP approach as well. Could be me, but many concepts in Rust reminded me a LOT of Haskell.
Of course Rust is not a pure FP language, so you can program procedurally if you want, but then in my opinion you're not using Rust's full power.
Let's figure out what is functional first. You mentioned Haskell, and even though it's been many years since I played with it, but if I'm not mistaken it doesn't allow mutation of a function arguments. So functions are pure: they take values and return a fresh value. Even though you can formally do the same with Rust, it won't work in practice, here's the example.
Suppose you have a Vector and a function
length(list: Vector<T>) -> i32
that returns length. If you call it on a vector, it'll be moved. And none of the subsequent calls on a variable holding that vector will work. Instead Rust encourages using borrowing:length(list: &Vector<T>) -> i32
and passing refs in this case. And in this case it's perfectly fine to call functions (procedures?) with refs multiple times.Now why I call these procedures:
do_something(&mut self)
would not return anything, and rather mutate the state of the struct it's attached to. So technically it's not a function, but a procedure that mimicks methods from OOP.And I guess it's perfectly fine, especially given that it's dictated by the reasons of performance and explicit resources control, but for someone with functional mindset (such as myself) it might be quite painful to adjust.
I won't argue with you on this particular example, but maybe the result (whether or not you run into these limitations) depends on how you approach the problem - point is I've seen (real world) Rust code on a project which looked and felt way more "FP" than procedural to me. But, it's more like I "dabbled" in Rust than that I could consider myself truly knowledgeable (let alone an expert) in it, I'm definitely not in a position to prove anything.
Some interesting points regarding whether or not Rust can be considered "functional":
fpcomplete.com/blog/2018/10/is-rus...
Funny, println was a Pascal statement 40 years ago.