Learn about data types in Rust using this tutorial and examples.
[lwptoc]
What is a Data Type?
A data type tells Rust compiler the kind of data being defined.
Are data types specification mandatory in Rust?
Yes. This is because Rust is a statically typed language. This implies that it must know the types of all variables at compile time.
However the compiler can usually infer what type we want to use based on the value and how we use it.
In cases when many types are possible, we must add a type annotation, like this:
let guess: u32 = "42".parse().expect("Not a number!");
Data Types in Rust can be divided into two subsets:
- Scalar
- Compound.
What is a Scalar Type?
A scalar type represents a single value.
What are the subcategories of Scalar type?
Rust has four primary scalar types:
- integers
- floating-point numbers
- Booleans
- characters. .
What are Integer Types?
An integer is a number without a fractional component.
One type of integer type is u32
type. This type declaration indicates that the value it’s associated with should be an unsigned integer (signed integer types start with i, instead of u) that takes up 32 bits of space.
What are the integer types in rust?
Here they are:
Length | Signed | Unsigned |
---|---|---|
8-bit | i8 |
u8 |
16-bit | i16 |
u16 |
32-bit | i32 |
u32 |
64-bit | i64 |
u64 |
128-bit | i128 |
u128 |
arch | isize |
usize |
Each variant can be either signed or unsigned and has an explicit size. Signed and unsigned refer to whether it’s possible for the number to be negative—in other words, whether the number needs to have a sign with it (signed) or whether it will only ever be positive and can therefore be represented without a sign (unsigned).
floating-point-types
Rust also has two primitive types for floating-point numbers, which are numbers with decimal points. Rust’s floating-point types are f32
and f64
, which are 32 bits and 64 bits in size, respectively. The default type is f64
because on modern CPUs it’s roughly the same speed as f32
but is capable of more precision.
Here's an example of floating point type:
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
Floating-point numbers are represented according to the IEEE-754 standard. The f32 type is a single-precision float, and f64 has double precision.
Numeric Operations
Rust supports the basic mathematical operations you’d expect for all of the number types: addition, subtraction, multiplication, division, and remainder. The following code shows how you’d use each one in a let
statement:
fn main() {
// addition
let sum = 5 + 10;
// subtraction
let difference = 95.5 - 4.3;
// multiplication
let product = 4 * 30;
// division
let quotient = 56.7 / 32.2;
// remainder
let remainder = 43 % 5;
}
The Boolean Type
As in most other programming languages, a Boolean type in Rust has two possible values: true
and false
. Booleans are one byte in size. The Boolean type in Rust is specified using bool
. For example:
fn main() {
let t = true;
let f: bool = false; // with explicit type annotation
}
The Character Type
So far we’ve worked only with numbers, but Rust supports letters too. Rust’s char
type is the language’s most primitive alphabetic type, and the following code shows one way to use it. (Note that char
literals are specified with single quotes, as opposed to string literals, which use double quotes.)
fn main() {
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';
}
Compound Types
Compound types can group multiple values into one type. Rust has two primitive compound types: tuples and arrays.
The Tuple Type
A tuple is a general way of grouping together a number of values with a variety of types into one compound type. Tuples have a fixed length: once declared, they cannot grow or shrink in size.
We create a tuple by writing a comma-separated list of values inside parentheses. Each position in the tuple has a type, and the types of the different values in the tuple don’t have to be the same. We’ve added optional type annotations in this example:
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
The variable tup binds to the entire tuple, because a tuple is considered a single compound element. To get the individual values out of a tuple, we can use pattern matching to destructure a tuple value, like this:
fn main() {
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is: {}", y);
}
The Array Type
Another way to have a collection of multiple values is with an array. Unlike a tuple, every element of an array must have the same type. Arrays in Rust are different from arrays in some other languages because arrays in Rust have a fixed length, like tuples.
In Rust, the values going into an array are written as a comma-separated list inside square brackets:
fn main() {
let a = [1, 2, 3, 4, 5];
}
To access array elements:
fn main() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
}
Example 1: Data Types simple example
This example will help you learn data types in Rust
Step 1: Create Project
- Open your
Rust
IDE. - In the menu go to
File --> Create New Project
.
Step 2: Add Dependencies
Go to your Cargo.toml
and modify it as follows:
[package]
name = "types"
version = "0.1.0"
authors = ["Inanc Gumus <[email protected]>"]
edition = "2018"
[dependencies]
Step 3: Write Code
Next create a file known as main.rs
and add the following code:
fn main() {
// err: parse cannot know the type of guess
.
// let guess = "42".parse().expect("Not a number!");
// here, we tell rust that guess is an u32 variable.
let guess: u32 = "42".parse().expect("Not a number!");
println!("{}", guess);
// ====================================================
// SCALAR TYPES
// Represent a single value.
// ====================================================
// INTEGERS:
// i8 to i128 and u8 to u128
// -> i means signed integer
// -> u means unsigned integer
// there are also:
// isize and usize.
//
// rust determines their sizes depending on the
// computer the compiler runs
//
// for example:
// on a 64-bit computer: isize is i64 and usize is u64.
// on a 32-bit computer: isize is i32 and usize is u32.
// INTEGER LITERALS:
let _ = 1_2_3; // decimal
let _: i64 = 0xdeadbeef; // hex
let _ = 0o444; // octal
let _ = 0b0101_1010; // binary
let _ = b'I'; // byte
// run with: cargo r -q --release
// to see the wrapping behavior.
//
// 255 + 1 becomes 0.
// 1111_1111 + 1 = 0000_0000
// let mut over: u8 = 255;
// over += 1;
// println!("over: {}", over);
let _ = 2.0; // f64
let _: f32 = 3.0; // f32
let _ = true || false; // bool
let _ = '💯'; // char
// TUPLES
let point = (10, 20.5);
let (x, y) = point;
println!("x: {}, y: {}", x, y);
println!("x: {}, y: {}", point.0, point.1);
// ARRAYS
let days = ["Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"];
println!("days: {}", days.join(", "));
// each element's type is i64
// and there are 5 elements.
let _: [i64; 5] = [1, 2, 3, 4, 5];
// 3 elements, each one is 1: [1, 1, 1]
let _ = [1; 3];
hello();
say(10, 20);
// {...} is an expression.
let (x, y) = {
let x = 1;
(x + 1, 5) // <- here it returns a tuple: (2, 5)
};
say(x, y);
say(one().0, one().1);
}
fn hello() {
println!("hello!");
}
fn say(n: i32, m: i64) {
println!("n: {}, m: {}", n, m);
}
fn one() -> (i32, i64) {
(1, 2)
}
Run
Copy the code, build and run.
Reference
Here are the reference links:
Number | Link |
---|---|
1. | Download Example |
2. | Follow code author |
3. | Code: Apache 2.0 License |