Unlocking the Power of Structs in Rust

What are Structs?

In the world of object-oriented programming, understanding the concept of structs is crucial for any developer. While languages like C, Go, and Rust don’t support classes, they use structs to define a group of properties instead. But what exactly are structs, and how do they operate in Rust?

Rust 101

Rust, a programming language created by Mozilla, is a fast, low-level language that uses modern syntax patterns and a central package manager. It’s similar to C, but with a more modern twist. In Rust, structs are used to define a group of properties, but they don’t allow you to define methods.

Writing a Struct in Rust

Let’s dive into an example of writing a simple struct for a Cat type that includes the properties name and age. We’ll define our struct, create a new instance of it, and print the entire struct using the {:?} formatter.

“`rust
struct Cat {
name: String,
age: u8,
}

fn main() {
let cat = Cat {
name: String::from(“Scratchy”),
age: 4,
};
println!(“{:?}”, cat);
}
“`

The Derive Attribute

By default, structs aren’t printable. To use the {:?} formatter with println!, we need to implement the std::fmt::Debug trait. But instead of doing it manually, we can use the derive(Debug) attribute to automate the implementation of certain traits on our struct.

Struct Traits

In Rust, traits define a bundle of functions for structs to implement. We can create a struct with properties, but how can we tie them to functions like we do with classes in other languages? The answer lies in traits.

Let’s define a trait called Pet that includes the functions birthday and sound. We’ll then implement this trait on our Cat and Dog structs.

“`rust
trait Pet {
fn birthday(&mut self);
fn sound(&self) -> String;
}

struct Cat {
name: String,
age: u8,
}

impl Pet for Cat {
fn birthday(&mut self) {
self.age += 1;
}
fn sound(&self) -> String {
String::from(“Meow”)
}
}

struct Dog {
name: String,
age: u8,
}

impl Pet for Dog {
fn birthday(&mut self) {
self.age += 1;
}
fn sound(&self) -> String {
String::from(“Ruff”)
}
}
“`

Returning a Struct

Sometimes, a function may return several possible structs that implement the same trait. To write this type of function, we can use the Box type to allocate enough memory for any struct implementing the Pet trait.

rust
fn new_pet(name: String) -> Box<dyn Pet> {
if name == "Scratchy" {
Box::new(Cat { name, age: 0 })
} else {
Box::new(Dog { name, age: 0 })
}
}

Summary

In this article, we’ve learned the following about structs in Rust:

  • Structs allow us to group properties in a single data structure
  • Using traits, we can implement different methods on a struct
  • Typing with traits allows us to write functions that can receive and return structs
  • The derive attribute allows us to implement certain traits in our structs with ease

With these concepts under our belt, we can now implement typical object-oriented design patterns in Rust using composition over inheritance.

Leave a Reply

Your email address will not be published. Required fields are marked *