$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh [...] 1) Proceed with installation (default) 2) Customize installation 3) Cancel installation >1 [...] To configure your current shell, run: source $HOME/.cargo/env $ $ source $HOME/.cargo/env $ rustc --version rustc 1.53.0 (53cb7b09b 2021-06-17) $
$HOME/.rustup$HOME/.cargo$HOME/.profile and $HOME/.bashrcrustc --version to verify the installation$ cp .profile .profile.orig $ cp .bashrc .bashrc.orig $ $ # install rust $ $ diff .profile.orig .profile 27a28 > . "$HOME/.cargo/env" $ diff .bashrc.orig .bashrc 128a129 > . "$HOME/.cargo/env" $The changes to
.profile and .bashrc are limited to sourcing the environment file.
Rust can be updated by rustup update and uninstalled by rustup self uninstall. rustup doc will open the documentation in a web browser.
*.rshello_world.rs)fn main() {
println!("Hello, world!");
}
fn main is the entrance point - like in C/C++rustfmt for automatic formatting.println!(...) calls a Rust macro - macros are handled later. println(...) would be a function call.$ mkdir Projects/playground/hello_rust $ cd Projects/playground/hello_rust $ vi main.rs $ rustc main.rs $ ls main main.rs $ ./main Hello, world! $ file main main: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=fcf290d46f244d46f80e05c5e5fa97eff197144b, with debug_info, not stripped $
*.rs file - in this example main.rsrustcmain$ cat main.rs
fn
main()
{
println!(
"Hello, world!"
);
}
$ rustc main.rs # compiles !
$ rustfmt main.rs # format with standard style
$ cat main.rs
fn main() {
println!("Hello, world!");
}
$
rustfmt to format your code to the official style guidecargo like this:
$ cargo new hello_cargo
Created binary (application) `hello_cargo` package
$ cd hello_cargo/
$ tree -a
.
├── Cargo.toml
├── .git
│ [...]
├── .gitignore
└── src
└── main.rs
10 directories, 18 files
$
.gitignoreCargo.toml in TOML format (Tom’s Obvious, Minimal Language) - the Cargo configurationsrc/main.rs template for source code (hello world)$ cat Cargo.toml [package] name = "hello_cargo" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] $
package section for configuring the package, the dependencies section for the dependencies.authors = ["Your Name <you@example.com>"] to the package section.$ cargo build
Compiling hello_cargo v0.1.0 (/home/krach/Projects/playground/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.35s
$
$ ./target/debug/hello_cargo
Hello, world!
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/hello_cargo`
Hello, world!
$
$ touch src/main.rs
$ cargo run
Compiling hello_cargo v0.1.0 (/home/krach/Projects/playground/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.14s
Running `target/debug/hello_cargo`
Hello, world!
$
cargo build builds the projectcargo build --release builds the project in release mode - which is faster but takes longer to compilecargo run runs the executable (and also builds it if needed)Cargo.lock keeps track of dependencies (cargo internal)cargo check checks that the code would compile - is much faster as cargo build - e.g. for IDE21:49:26[rust]$ rustc --version
rustc 1.51.0
21:49:34[rust]$ cargo new guessing_game
Created binary (application) `guessing_game` package
21:49:55[rust]$
And compiling and running the code...
21:49:55[rust]$ cd guessing_game/
21:51:02[guessing_game]$ cargo run
Compiling guessing_game v0.1.0 (/home/charly/tmp/rust/guessing_game)
Finished dev [unoptimized + debuginfo] target(s) in 0.70s
Running `target/debug/guessing_game`
Hello, world!
21:51:18[guessing_game]$
In the next steps we expend the code:
using we can bring a library into scope. Without the using std::io term we have to write std::io::stdin() instead of io::stdin(). There is a default set of type in scope - called the prelude.let foo = 5; creates a constant (immutable) whilelet mut bar = 42; creates a variable (mutable).let mut guess = String::new(); creates a variable guess with a "growable, UTF-8 encoded bit of text".::new means calling a associated function of the String type - in c++ a static function. The new function creates a empty string and is available on many types.& - mutable variables with &mut. So calling the method fn read_line(buf: &mut String) looks like that: read_line(&mut guess)io::Result is an enumeration which can hold one value of a fix set of values (in our case Ok and Err), called enum's variants.Results are tuples which hold a (return) value and an error code - e.g. in this case String and io::Error. This allows in the OK-case to work with the return value - and in error case to work with the error code.io::Result has an expect method which acts like an assert in case of an error. In case of no error, it simply returns the value.Result but not handling the error code - e.g. with expect().println! you can use {} as placeholder for a value, e.g. println!("x = {} and y = {}", x, y);String to i32.0.8.3 means that all crates greater equal 0.8.3 up to (exclusive) 0.9.0 may be used.Cargo.lock file specifies which concrete version is used - in this case 0.8.4. It is added to the versioning system. Explicit updates are done with cargo update.10:48:03[guessing_game]$ cat Cargo.lock | grep package | wc -l
1
10:48:15[guessing_game]$ ls -l target/debug/guessing_game
-rwxrwxr-x 2 charly charly 10794144 Aug 28 22:01 target/debug/guessing_game
10:48:19[guessing_game]$ gvim Cargo.toml
10:48:25[guessing_game]$ git diff --unified=0 Cargo.toml | tail -n +5
@@ -9,0 +10 @@ edition = "2018"
+rand = "0.8.3"
10:48:45[guessing_game]$ cargo build
Updating crates.io index
Finished dev [unoptimized + debuginfo] target(s) in 0.83s
10:48:53[guessing_game]$ ls -l target/debug/guessing_game
-rwxrwxr-x 2 charly charly 10794152 Aug 29 10:39 target/debug/guessing_game
10:48:55[guessing_game]$
10:48:58[guessing_game]$ cat Cargo.lock | grep package | wc -l
10
10:49:00[guessing_game]$
Result the compiler generates a warning when the error-code is not checked. This can be done in two ways. When an error is not expected, the expect() method can be used - it works like an assert and crashes the program when an error appears:
let guess: u32 = guess.trim().parse().expect("Please type a number!");
When it is likely that the method returns an error - e.g. in user-interaction - the error shall be handled:
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(e) => {
println!("Got invalid input: {}", e);
continue
},
};
let x = 7;let mut y = 8;const Z: i32 = 9; (snake_case)error[E0282]: type annotations needed says that Rust cannot figure out the correct type, e.g. in let guess: i32 = "42".parse().expect("Not a number!");i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize (where the last two are architecture dependent, e.g. 64 bit on a 64-bit machine)12_000 for 12000 (like in C++14 as 12'000)98_222), hex (0x1_7F_AE), octal (0o27_76_56) and binary (0b0001_0111_1111_1010_1110). Bytes (u8) can be written like this: b'A'wrapping_ (for explicitly wrapping around), checked_ (returns None on overflow), overflowing_ (provides additional bool) and saturating_ (staying at max/min).f32 and f64. f64 is the default because on modern machines they have roughly the same speed as f32.bool with true and false as values.char: let heart_eyed_cat = '😻'; It's Unicode and with a size of 4 bytes.let first_tup = (500, 6.4, 1); let second_tup: (i32, f64, u8) = (500, 6.4, 1); // same as first_tup let (x, y, z) = first_tup; // called destructing let five_hundred = second_tup.0; let six_point_four = second_tup.1;
let a = [1, 2, 3, 4, 5]; let b: [i32; 5] = [1, 2, 3, 4, 5]; // same as array a let c = [1; 5]; // creates [1, 1, 1, 1, 1] (value is 1, size is 5) let first = a[0]; let second = a[1];
fn another_function(x: i32) {let y = 6;fn main() {
let y = 6;
}5 + 6{
let x = 3;
x + 1
}fn plus_one(x: i32) -> i32 {
x + 1
}return keywordif, else, else if, loop, while and for
if number < 5 {
println!("small number");
} else if number > 100 {
println!("big number");
} else {
println!("regular number");
}bool.else if you might refactor your code with the match statementlet number = if value != 7 { 5 } else { 6 }; (both arms must have the same type, e.g. i32)loop:
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
while loop:
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("the value is: {}", a[index]);
index += 1;
}
for loop and iterator:
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!("the value is: {}", element);
}
for loop:
for number in (1..4).rev() {
println!("{}!", number);
}