Monday, May 1, 2023

First Steps in Rust





In this post we will review how to get familiar with Rust programming language.


Useful resource is "The Book", that is the Rust Programming Language book.


Installation

To install Rust, use the following:


curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh


The latest version we're using in this post is 1.69.0. In case of need, rust version can be updated using:


rustup update


Using Rust requires us to use the cargo tool, which is a build tool and a package manager.

Create a New Project

Let start with a new project:


cargo new hello-world


I am using JetBrains GoLand IDE with Rust plugin installed to edit the code, and run the project, but in general, we can run the project using:


cargo run


To add dependencies, add in the project manifest file, Cargo.toml the required libraries:

[dependencies]
ferris-says = "0.3.1"


and now, we can use the dependency:


use ferris_says::say;
use std::io::{stdout, BufWriter};

fn main() {
let stdout = stdout();
let message = String::from("Hello World!");
let width = message.chars().count();

let mut writer = BufWriter::new(stdout.lock());
say(&message, width, &mut writer).unwrap();
}


The output is:




Dependencies

The file cargo.lock specific all transitive dependencies used by the project. The cargo.lock file is created upon the first build, and it updated when updating the dependencies in the cargo.toml file.

To add a dependency, add under the [dependencies] section in the cargo.toml the library needed and its version. Cargo will look for the highest version without API change. For example, version 1.2.3 in the cargo.toml might eventually be resolved to 1.2.9 in the cargo.lock, but not to 1.3.0.

Once entered to the cargo.lock file, dependencies versions are no longer updated. To force update of the lock file, use:


cargo update


To create documentation for the project and all its dependencies, use:


cargo doc --open


Functions

functions:

fn my_function(){

}


Call to function:

my_function();


Call to macro (notice the '!' at the end):

println!()


Function with return value should not include ';' in the return statement (the last statement):

fn add(i1: i32, i2: i32) -> i32 {
i1 + i2
}


alternatively use explicit return statement:

fn add(i1: i32, i2: i32) -> i32 {
return i1 + i2;
}


Variables

Mutable variables:

let non_mutable_variable = 5;
let mut mutable_variable = 4;

// compile error
non_mutable_variable = 8;
// but this one is ok
mutable_variable = 8;


Sending variables by reference:

io::stdin().read_line(&mut guess)


Variable shadowing (useful for convert between types):

let i=5;
let i=String::from("fff");


Constants must include the type as part of the declaration.

const COUNT: u32 = 33;


Tuples

Create and use tuple:
let my_tuple = (1, 'a', "bb");
let first = my_tuple.0;
let third = my_tuple.2;
println!("my tuple elements are {first} {third}")

The empty tuple is called unit:
let empty_tuple =();

Arrays

Fixed length arrays, whose size cannot be changed.
let my_array = [0, 1, 2, 3, 4, 5];

Arrays can be initialized to the same value for all items:
let array_of_many_fives = [5; 100];

Arrays types can be explicitly configured:
let mut explicit_type_array: [i32; 5] = [0; 5];
explicit_type_array[0] = 1

Notice that out of array bounds access is checked in runtime (unlike C)

Ranges

range inclusive

1..=100

range exclusive

1..100

Reversed range:

(0..10).rev()


Loops

While loop:

let mut i = 0;
while i < 10 {
i += 1;
}


Loop on range:

for i in 0..10 {
println!("{i}");
}


Loops and break:

loop {
if 1 == 1 {
break;
}
}


A loop can also return values:

let the_answer = loop {
if 1 == 1 {
break 42;
}
};
println!("{the_answer}")


Conditional Expressions

if statements can return a value, for example as one line initialization:
let number = 5;
let other_number = if number > 5 { "big" } else { "small" };
println!("{}", other_number);

Results and ARM

Handling Result type:

let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("numbers only please");
continue;
}
};


arm: pattern to match against, and code to run:

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}


IO Library

to use the library:

use std::io;


Print macro with variables:

println!("You guessed: {guess}");


No comments:

Post a Comment