Login Register
×

What Is a Structs In Rust?

What are Structs?

A struct is short for structure. It’s like a container that groups different pieces of data under one name. Structs are similar to objects in object-oriented programming, but a struct itself doesnโ€™t have methods; it only stores data.

  • It can hold different types of values, such as a number, a string, a Boolean.
  • It’s like creating your own “data model” (such as a student, book, or car).

Types of Structs in Rust

Rust provides us with different styles of structs, depending on how we want to represent that data.

1) Named Field Structs: This is the most common type of struct. Each field inside the struct has a name and a data type.

For example, if you are building a library system, you may want to store information about a book, such as its title, the number of pages, and its price.

Code example:

struct Book {
title: String,
pages: u32,
price: f32,
}

fn main() {
let book1 = Book {
title: String::from("Rust Guide"),
pages: 250,
price: 19.99,
};

println!("{} has {} pages and costs ${}", book1.title, book1.pages, book1.price);
}
  • Here, the name title, pages, and price clearly describe what each value represents.

2) Tuple Structs: Tuple structs look like regular tuples, but they are given a custom type name. The field doesn’t have names; they are accessed by their position index.

Suppose you want to represent colors using three numbers (RGB). Instead of naming each field, you can just group them. For example:

struct Color(u8, u8, u8);

fn main() {
let red = Color(255, 0, 0);
println!("Red color values: {}, {}, {}", red.0, red.1, red.2);
}
  • Here, Color(255, 0, 0) represents the RGB values for red. Tuple structs are useful when naming each field separately doesnโ€™t add much value.

3) Unit-like Structs: Sometimes, you may not need to store any data at all; you just want to create a type that can act as a marker or tag. For this reason, unit-like structs are used.

For example:

struct Logger;

fn main() {
let log = Logger; // Just an instance, holds no data
println!("Logger struct created!");
}

How To Use Named Field Structs In Rust?

A Named Field Struct is a way to group related data together, where each piece of data has a clear name. This makes our code easier to read and understand.

Imagine, it’s like a “profile-card” that has a name, an age, and a status like student or not. Each of these is a field inside the struct. You can then create instances (actual “cards”) with specific values and access their data easily.

Example:

// Defining a Named Field Struct
struct Car {
brand: String,
year: u32,
is_electric: bool,
}

fn main() {
// Creating an instance of the struct
let my_car = Car {
brand: String::from("Tesla"),
year: 2023,
is_electric: true,
};

// Accessing fields
println!("Brand: {}", my_car.brand);
println!("Year: {}", my_car.year);
println!("Is Electric: {}", my_car.is_electric);
}

Output:

Brand: Tesla
Year: 2023
Is Electric: true

Explanation of this code:

  • struct Car { . . . } โ†’ Defines a new data type called Car with three named fields: brand, year, and is_electric.
  • let my_car = Car { . . . }; โ†’ Creates a specific car instance with actual values.
  • my_car.brand โ†’ Accesses the brand field of this car.

How To Use Tuple Structs In Rust?

A Tuple Struct is a way to group related data without giving names to each field, but the struct itself has a name.

Example:

// Defining a Tuple Struct
struct Point(i32, i32, i32);

fn main() {
// Creating an instance of the tuple struct
let my_point = Point(10, 20, 30);

// Accessing values using index
println!("X: {}", my_point.0);
println!("Y: {}", my_point.1);
println!("Z: {}", my_point.2);

// Using the values in a calculation
let sum = my_point.0 + my_point.1 + my_point.2;
println!("Sum of coordinates: {}", sum);
}

Output:

X: 10
Y: 20
Z: 30
Sum of coordinates: 60

Explanation:

  • struct Point(i32, i32, i32); โ†’ Defines a new type Point with three fields (all integers), but no field names.
  • let my_point = Point(10, 20, 30); โ†’ Creates an instance of Point with values 10, 20, 30.
  • my_point.0, my_point.1, my_point.2 โ†’ Access fields by their index.

How To Use Unit-like Structs In Rust?

A Unit-like Struct is a struct that has no fields at all. It doesnโ€™t store any data.

They are especially useful when you want to:

  • Create a unique type to distinguish values.
  • Implement traits on something that doesnโ€™t need data.

Example:

// Defining a Unit-like Struct
struct Logger;

fn main() {
// Creating an instance
let log = Logger;

// Using it to indicate a behavior
print_message(log);
}

// Function that accepts Logger type
fn print_message(_: Logger) {
println!("This is a special logger type!");
}

Output:

This is a special logger type!

Struct Updates Using Struct Update Syntax

Rust allows you to create a new instance of a struct by copying fields from another instance using the . . syntax.

Example:

// Define a Person struct
struct Person {
name: String,
age: u32,
is_student: bool,
}

fn main() {
// Original person
let person1 = Person {
name: String::from("John"),
age: 22,
is_student: true,
};

// Create a new person using struct update syntax
let person2 = Person {
name: String::from("Emma"), // only name is changed
..person1 // rest of the fields copied from person1
};

println!("Person2 Details: Name: {}, Age: {}, Is Student: {}",
person2.name, person2.age, person2.is_student);
}

Output:

Person2 Details: Name: Emma, Age: 22, Is Student: true

Methods in Structs

In Rust, methods let you attach functions directly to a struct. This allows the struct to do actions related to itself, instead of writing separate functions.

Methods help organize code and make it more readable and structured.

impl block โ†’ Where you define all methods for a struct.

&self โ†’ Means the method can read data from the struct without taking ownership.

Example:

// Define a Rectangle struct
struct Rectangle {
width: u32,
height: u32,
}

// Implement methods for Rectangle
impl Rectangle {
// Method to calculate area
fn area(&self) -> u32 {
self.width * self.height
}

// Method to calculate perimeter
fn perimeter(&self) -> u32 {
2 * (self.width + self.height)
}
}

fn main() {
let my_rect = Rectangle {
width: 15,
height: 25,
};

println!("Rectangle Area: {}", my_rect.area());
println!("Rectangle Perimeter: {}", my_rect.perimeter());
}

Output:

Rectangle Area: 375
Rectangle Perimeter: 80

Exercise: Book Library Struct

create a small library system. Each book has a title, author, and number of pages.

Your task:

  1. Create a struct Book with fields title, author, and pages.
  2. Add a method is_long that returns true if the book has more than 300 pages.
  3. Add another method summary that prints the title and author in a sentence.
  4. Create at least two books and test the methods.
// Define the Book struct
struct Book {
title: String,
author: String,
pages: u32,
}

// Implement methods for Book
impl Book {
// Method to check if book is long
fn is_long(&self) -> bool {
self.pages > 300
}

// Method to print a short summary
fn summary(&self) {
println!("'{}' is written by {}.", self.title, self.author);
}
}

fn main() {
let book1 = Book {
title: String::from("Rust Programming Basics"),
author: String::from("Alice"),
pages: 250,
};

let book2 = Book {
title: String::from("Mastering Rust"),
author: String::from("Bob"),
pages: 400,
};

// Test methods
book1.summary();
println!("Is it a long book? {}\n", book1.is_long());

book2.summary();
println!("Is it a long book? {}", book2.is_long());
}

Output:

'Rust Programming Basics' is written by Alice.
Is it a long book? false

'Mastering Rust' is written by Bob.
Is it a long book? true

Learn More About Rust Programming