Focus mode

Rust Programming

Basic data types and variables

Welcome to the lecture on basic data types and variables in Rust! In this lecture, we'll go over the different data types that Rust offers, and how to declare and use variables in your Rust programs. 

Data Types

Rust has several built-in data types that you can use in your programs. Here are the most common ones:

  • Booleans: bool, which can have the values true or false
  • Integers: i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, which are signed and unsigned integers of different sizes
  • Floating-point numbers: f32 and f64, which are single-precision and double-precision floating-point numbers, respectively
  • Characters: char, which represents a single Unicode character
  • Strings: &str and String, which represent a sequence of Unicode characters
  • Arrays: [T; N], which represent a fixed-size array of elements of type T
  • Slices: [T] and &[T], which represent a variable-size sequence of elements of type T
  • Tuples: (T1, T2, ..., Tn), which represent a fixed-size sequence of elements of different types
  • Unit type: (), which represents an empty tuple and is used when no value is needed

Let’s have a closer look at these data types.

Booleans

Booleans in Rust are a data type that represents a value that can be either true or false. They are often used in programming to represent the truth value of a statement or condition. In Rust, you can declare a boolean variable using the let keyword, followed by the variable name and the value you want to assign to it. Here's an example:

let is_rust_fun = true;


In this example, we declare a variable called is_rust_fun and assign it the value true. You can also declare boolean variables with the value false, like this:

let is_rust_hard = false;

Boolean values are used to test for conditions and control the flow of execution in your program. You'll find yourself using booleans in Rust frequently as you write more complex programs.

Integers

Integers in Rust are a data type that represents whole numbers. Rust has several built-in integer types, ranging from 8-bit to 128-bit signed and unsigned integers. Rust's integer types differ from those in some other programming languages in that they have a fixed bit size, meaning that they can only hold a certain range of values based on their size. This makes Rust's integer types more safe and less prone to integer overflows or underflows.

In Rust, you can declare an integer variable using the let keyword and specifying the type using a colon (:), like this:

let x: i32 = 42;


In this example, we declare a variable called x of type i32 and assign it the value 42. Rust has several built-in integer types, including signed and unsigned integers of different sizes. Here are the most common ones:

  • i8 and u8: 8-bit signed and unsigned integers, respectively
  • i16 and u16: 16-bit signed and unsigned integers, respectively
  • i32 and u32: 32-bit signed and unsigned integers, respectively
  • i64 and u64: 64-bit signed and unsigned integers, respectively
  • i128 and u128: 128-bit signed and unsigned integers, respectively

One thing to note about Rust's integer types is that they use a two's complement representation for signed integers. This means that the leftmost bit is used as the sign bit, with 0 indicating a positive number and 1 indicating a negative number. The remaining bits represent the absolute value of the number.

Rust's integer types also have specific minimum and maximum values based on their size, which you can access using the MIN and MAX constants. Here's an example:

let min_i32 = i32::MIN;
let max_i32 = i32::MAX;

println!("The minimum value of i32 is {} and the maximum value is {}.", 
    min_i32, max_i32);


In addition to the standard arithmetic operators (+, -, *, /, %), Rust's integer types also support bitwise operators (&, |, ^, <<, >>) for manipulating individual bits.

That's a brief overview of integers in Rust! With Rust's fixed bit size and safe integer handling, you can be sure that your programs will be less prone to integer overflows and underflows. As they say in the Rust community, "In Rust, you can have your bits and eat them too!"

Floating Point Numbers

Floating-point numbers in Rust are a data type that represents numbers with a fractional part. Rust has two built-in floating-point types, f32 and f64, which are single-precision and double-precision floating-point numbers, respectively. You can declare a floating-point variable using the let keyword and specifying the type, like this:

let pi: f64 = 3.14159;


In this example, we declare a variable called pi of type f64 and assign it the value 3.14159. Rust's floating-point types support the standard arithmetic operators (+, -, *, /) and comparison operators (<, >, <=, >=, ==, !=).

Floating-point numbers have some limitations due to their inherent precision limitations. Therefore, it is important to use them carefully in certain situations, especially when dealing with financial calculations, where rounding errors can lead to incorrect results.

That's a brief overview of floating-point numbers in Rust! They're a useful data type for representing numbers with a fractional part, and Rust's built-in floating-point types make it easy to work with them in your programs.

Characters

Characters in Rust are represented using the char type, which can hold any Unicode character. You can declare a character variable using the let keyword and enclosing the character in single quotes ('), like this:

let letter_a: char = 'a';

Strings

Strings in Rust are a data type that represents a sequence of Unicode characters. Rust has two built-in string types, &str and String. &str is a reference to a string slice, while String is a growable string type.

You can declare a string slice variable using the & operator, followed by the string literal enclosed in double quotes ("), like this:

let message: &str = "Hello, world!";


In this example, we declare a variable called message of type &str and assign it the value "Hello, world!". String slices are immutable by default, meaning that you can't modify the string once it's been created.

You can also create a String variable, which is a growable string type, using the let keyword and the String::from method:

let mut name = String::from("Alice");


In this example, we declare a mutable variable called name of type String and assign it the value "Alice". Unlike string slices, String variables are mutable by default, meaning that you can modify the string's contents.

It's important to note that there is a difference between a String and a string slice (&str) in Rust. A String is a growable string type that is stored in the heap, while a string slice (&str) is a reference to a fixed-size sequence of characters that can be stored either in the heap or in the program's binary. This topic is comprehensive and will be covered in more depth in future lectures.

Arrays

Arrays in Rust are a data type that represents a fixed-size sequence of elements of the same type. You can declare an array variable using the let keyword, followed by the variable name, the array length enclosed in square brackets ([]), and the type of the elements, like this:

let numbers: [i32; 3] = [1, 2, 3];


In this example, we declare an array called numbers of length 3 and type i32, and assign it the values 1, 2, and 3. You can access individual elements of the array using indexing, like this:

let second_number = numbers[1];
println!("The second number in the array is {}.", second_number);


In this example, we use indexing to get the second element of the array (which has an index of 1) and assign it to the second_number variable. We then print the value of second_number to the console.

Slices

Slices in Rust are a data type that represents a variable-size view into a contiguous sequence of elements of the same type. You can declare a slice variable using the let keyword, followed by the variable name, a reference to an array, and a range of indices enclosed in square brackets ([]), like this:

let slice = &numbers[1..3];


In this example, we declare a slice called slice that contains the elements of the numbers array with indices 1 and 2 (but not 3). You can access individual elements of the slice using indexing, like this:

let first_element = slice[0];
println!("The first element of the slice is {}.", first_element);


In this example, we use indexing to get the first element of the slice and assign it to the first_element variable. We then print the value of first_element to the console.

Tuples

Tuples in Rust are a data type that represents a fixed-size sequence of elements of different types. You can think of a tuple as a lightweight data structure that lets you group multiple values together into a single entity. Tuples are immutable by default, meaning that you can't modify the elements once the tuple has been created.

You can declare a tuple variable using the let keyword, followed by the variable name, and a comma-separated list of values enclosed in parentheses (()), like this:

let person = ("Alice", 30);


In this example, we declare a tuple called person that contains a string ("Alice") and an integer (30). You can access individual elements of the tuple using indexing, like this:

let name = person.0;
let age = person.1;
println!("The person's name is {} and their age is {}.", name, age);


In this example, we use indexing to get the first element of the tuple (which has an index of 0) and assign it to the name variable. We then use indexing to get the second element of the tuple (which has an index of 1) and assign it to the age variable. We then print the values of name and age to the console.

Tuples in Rust can also be nested, meaning that you can have a tuple within a tuple. Here's an example:

let person = (("Alice", "Smith"), 30);
println!("The person's name is {} {} and their age is {}.", person.0.0, person.0.1, person.1);


In this example, we declare a nested tuple called person that contains another tuple of strings (("Alice", "Smith")) and an integer (30). We then use indexing to get the first element of the outer tuple (which is the inner tuple), and then use indexing again to get the first and second elements of the inner tuple (which are the first and last names). We then use indexing to get the second element of the outer tuple (which is the age). We then print the person's name and age to the console.

Unit Type

The unit type in Rust is a data type that represents a value that has no meaningful information. You can declare a unit variable using the let keyword and a pair of empty parentheses (()), like this:

let result = do_something();
println!("The result is {}.", result);


In this example, we call a function called do_something() and assign its result to a variable called result. Because do_something() returns the unit type (()), the result variable doesn't contain any meaningful information. We then print the value of result to the console, but it will just be an empty pair of parentheses (()).

Variables

In Rust, a variable is a named storage location in memory that holds a value of a certain type. Variables can be declared using the let keyword, followed by the variable name, an optional type annotation, and an equals sign (=) followed by the value that the variable should hold.

Here's an example of declaring a variable and assigning it a value:

let x: i32 = 42;


In this example, we declare a variable called x of type i32 (a 32-bit signed integer) and assign it the value 42.

In Rust, variables are immutable by default, meaning that you can't change their value once they've been assigned. If you try to assign a new value to an immutable variable, you'll get a compiler error.

let x = 42; // immutable variable
x = 10; // error: cannot assign twice to immutable variable


To make a variable mutable, you can use the mut keyword before the variable name:

let mut x = 42; // mutable variable
x = 10; // OK!


In this example, we declare a mutable variable called x and assign it the value 42. We then assign it a new value of 10.

Rust also has type inference, which means that the compiler can automatically infer the type of a variable based on its value. Here's an example:

let y = 3.14; // Rust infers the type as f64


In this example, we declare a variable called y and assign it the value 3.14. Rust infers the type of y as f64 (a 64-bit floating-point number) based on the value.

Rust also supports shadowing, which means that you can declare a new variable with the same name as an existing variable in a more nested scope. Here's an example:

let x = 42;
let x = x + 1;


In this example, we declare a variable called x and assign it the value 42. We then declare a new variable called x in a more nested scope, which shadows the outer x variable. We assign the new x variable the value of the old x variable plus 1.

Variables are a fundamental concept in programming, and Rust's support for both immutable and mutable variables, type inference, and shadowing makes it a powerful tool for creating robust and flexible programs.

Test

Comments

You need to enroll in the course to be able to comment!