0% found this document useful (0 votes)
3 views

levelup.gitconnected.com-Basics of Rust Programming Part-2 A Comprehensive Tutorial for Beginners

Uploaded by

udaycignex
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

levelup.gitconnected.com-Basics of Rust Programming Part-2 A Comprehensive Tutorial for Beginners

Uploaded by

udaycignex
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

Basics of Rust Programming (Part-2): A Comprehensive

Tutorial for Beginners


levelup.gitconnected.com/basics-of-rust-programming-part-2-a-comprehensive-tutorial-for-beginners-494c38d50535

AI TutorMaster July 23, 2023

Learn the basics of Rust programming with comprehensive tutorial

BY- Authour

In this comprehensive tutorial, we delve into the basics of Rust programming, a powerful
language renowned for its performance and memory safety features. Ideal for beginners and
experienced developers alike, this guide covers everything from syntax and basic concepts
to advanced topics like concurrency and error handling. Learn about Rust’s unique features
such as ownership, borrowing, lifetimes, and its robust type system and macro system.

Discover how Rust handles functions, error handling, enums, pattern matching, and
non-exhaustive enums. We explored examples, syntax, and best practices,
emphasizing Rust’s focus on safety and control flow.

This Rust programming tutorial serves as a valuable resource for anyone looking to
master this versatile language. Whether you’re just starting out with Rust or need a
quick refresher on specific concepts, this guide is the perfect companion on your
learning journey. Remember, the strength of the Rust community lies in collaborative
learning, so don’t hesitate to share your feedback and suggestions for improvement.
Happy learning!

Here are some Key concept in detail i have explained in other Blogs:

Basics of Rust Programming (Part-1): A Comprehensive Tutorial for


Beginners

Learn the basics of Rust programming with comprehensive tutorial


levelup.gitconnected.com

Functions
A function is a named sequence of statements that performs computations or actions, taking
inputs (parameters) and optionally returning a value.

Defining and Calling a Function

1/6
Functions are defined using the fn keyword. The general structure of a function is as follows:

(: Type1, : Type2, ...) > { }

Let’s consider a simple example where we define a function that adds two numbers and
returns their sum:

(x: , y: ) { x + y }

To call this function, you can use the following syntax:

= add_two_numbers(5, 6);println!(, );

Function Parameters
Parameters allow us to pass values into functions. They are specified in the function
definition and hold the values passed when the function is called.

For instance, consider the following function that prints the sum of two numbers:

(a: , b: ) { = a + b; (, a, b, sum);}

Returning Values from Functions


Functions in Rust can return values. The return value is determined by the final expression in
the function’s body. Although you can explicitly use the return keyword to exit early from a
function and specify a value, most functions return the last expression implicitly.

Here’s an example of a function that returns a boolean value:

(num: ) { num % == }

It’s important to note that functions in Rust create a new scope for variables. This concept
introduces important ideas such as shadowing and ownership, which are crucial aspects of
Rust’s memory management system.

Error Handling
In Rust, errors are categorized into two main types: recoverable and unrecoverable errors.
Recoverable errors, such as a file not found error, can be reported to the user and retried.
Unrecoverable errors, on the other hand, indicate bugs in the program and cause the
program to stop execution. I have written in detail about it in my other blog too .

Mastering “Rust” Programming (Part-1): A Beginners Guide to


System-Level Programming and Concepts

2/6
Unraveling the concepts of Ownership, Borrowing and Lifetimes, Slices and
Advanced Concepts in Rust Programming”

levelup.gitconnected.com

Unlike languages with exceptions, Rust uses the Result<T, E> type for recoverable errors
and the panic! macro for unrecoverable errors.

Here’s a basic example demonstrating the use of Result:

(dividend: , divisor: ) <, > { divisor == { (::()) } {


(dividend / divisor) }}

To handle the Result, you can use a match expression:

(, ) { (result) => (, result), (msg) => (, msg),}

Rust provides the ? operator, which simplifies error handling in functions that return Result:

() <(), < std::error::Error>> { = (, )?; (, result); (())}

In the above example, if the division function returns Err, the error will be propagated
up to the main function. If it returns Ok, the value inside Ok will be assigned to result.

Additionally, you can define your own error types in Rust:

{ (std::::), (std::::),}

impl From<std::io::Error> for MyError { fn from(err: std::io::Error) -> MyError {


MyError::Io(err) }}impl From<std::num::ParseIntError> for MyError { fn
from(err: std::num::ParseIntError) -> MyError { MyError::Parse(err) }}

For more advanced error handling, you can use the thiserror crate, which automates the
process of creating custom error types and implementing the Error trait:

1. Add thiserror to your Cargo.toml dependencies.


2. Use #[derive(thiserror::Error)] to create your custom error type.

Here’s an example:

thiserror::Error; { ( std::io::Error), ( std::num::ParseIntError),


}

You can then use this custom error type in functions that return Result:

std::fs::File; () <(), MyError> { = File::()?; (())}

To make your code future-proof, you can use the #[non_exhaustive] attribute, which allows
the enum to be extended with additional variants in future versions of the library.

3/6
This advanced error handling approach provides a robust and flexible way to manage
errors in Rust, especially for library authors.

You can use this custom error type in functions that return Result:

use std::fs::File;

() <(), MyError> { = File::()?; (())}

To ensure your code is future-proof against changes to the Error enum, Rust has the #
[non_exhaustive] attribute. When this is added to your enum, it becomes non-exhaustive,
and can therefore be extended with additional variants in future versions of the library:

{ (std::io::Error), (std::num::ParseIntError), }

Now, when matching on this Error enum outside of the crate it's defined in, Rust will enforce
that a _ case is included:

error { Error::(err) => (, err), Error::(err) => (, err), _ => (),}

This advanced error handling approach provides a robust and flexible way to manage errors
in Rust, particularly for library authors.

Enums and Pattern Matching


Enums, short for enumerations, allow you to define a type by specifying its possible values.
Each variant of an enum is a separate type. You can also associate data with enum variants.

Here’s an example of defining an enum:

{ North, South, East, West,}

Enums can also have variants with associated data:

{ (), Missing,}

Pattern matching is a powerful feature in Rust that allows you to match against
different cases of an enum with a clean syntax. It ensures that all possible cases are
handled.

Here’s an example of using pattern matching with enums:

= Direction::North; direction { Direction::North => (), Direction::South =>


(), Direction::East => (), Direction::West => (),

Rust also provides the if let construct as a more concise alternative to match when
you are interested in only one case:

4/6
= OptionalInt::(); ::(i) = optional { (, i);} { ();}

You can define methods on enum variants using the impl keyword:

{ Quit, (, , ), (),} { (&) { }} = Message::(::());m.();

Rust’s enums and pattern matching provide a flexible and expressive way to handle
different cases and control flow in your code.

Non-exhaustive Enums and Structs


In Rust, the #[non_exhaustive] attribute is used to mark enums or structs as non-
exhaustive. This feature ensures that they are not exhaustively matched upon outside the
crate they are defined in. It allows for adding more variants or fields to the enum or
struct in the future without breaking existing code.

Here’s an example of a non-exhaustive enum:

{ (std::io::Error), (std::num::ParseIntError), }

When matching on a non-exhaustive enum outside of its crate, you must include a _
case to handle potential future variants:

error { Error::(err) => (, err), Error::(err) => (, err), _ => (),}

If the _ case is not included, the code won't compile. This ensures that your code is future-
proof against changes to the enum.

The #[non_exhaustive] attribute can also be used with structs to prevent them from
being destructured outside of their defining crate, allowing for adding more fields
without breaking existing code.

This feature of Rust provides forward compatibility, allowing for extending enums and structs
in libraries without causing breaking changes.

Ownership, Borrowing, and Lifetimes


Ownership is a key concept in Rust that ensures memory safety without the need for
garbage collection. It revolves around three main rules:

1. Each value in Rust has a variable that’s called its owner.


2. There can only be one owner at a time.
3. When the owner goes out of scope, the value will be dropped.

= ::(); = s1;

5/6
Borrowing is another key concept in Rust, which allows you to have multiple references to a
value as long as they’re not conflicting. There are two types of borrows: mutable and
immutable.

= ::(); = &s; = &s;

Lifetimes are a way for the Rust compiler to ensure that references are always valid. It’s an
advanced concept in Rust and usually, the compiler can infer lifetimes in most cases. But
sometimes, you might have to annotate lifetimes yourself:

<>(x: & , y: & ) & { x.() > y.() { x } { y }}

In the example above, the function longest returns the longest of two string slices. The
lifetime annotation 'a indicates that the returned reference will live at least as long as the
shortest of the two input lifetimes.

Mastering “Rust” Programming (Part-1): A Beginners Guide to


System-Level Programming and Concepts

Unraveling the concepts of Ownership, Borrowing and Lifetimes, Slices and


Advanced Concepts in Rust Programming”
levelup.gitconnected.com

Ownership, Borrowing, and Lifetimes are crucial to understanding how Rust manages
memory and ensures safety. The Rust compiler enforces these rules at compile time, which
allows for efficient and safe programs.

6/6

You might also like