Sling Academy
Home/Rust/Defining Structs as “Objects” in Rust: Fields and Methods

Defining Structs as “Objects” in Rust: Fields and Methods

Last updated: January 06, 2025

In the programming language Rust, defining structs as objects is a common practice that helps in handling complex data efficiently. Structs allow you to create custom data types by bundling related values called fields. To further enhance their functionality, you can also define methods for these structs, allowing them to behave more like objects in other object-oriented languages. This article explores how to define structs, create methods, and use them as objects in Rust.

Defining a Struct

In Rust, a struct is defined using the struct keyword followed by the name of your struct and the fields it contains. Each field has a name and a type, and you must specify them at the time of defining the struct. Let us start by defining a simple struct for a 2D point:

struct Point {
    x: i32,
    y: i32,
}

Here, Point is a struct with two fields, x and y, both of which are 32-bit integers. Once defined, you can create instances of this struct:

let origin = Point { x: 0, y: 0 };
let another_point = Point { x: 20, y: 30 };

Methods and Associated Functions

Methods in Rust are similar to functions but are associated with a particular struct. You define methods inside an impl block, allowing each struct to hold functions that can act on its fields.

Defining Methods

Let us add a method to calculate the distance from another point. This method, distance_from, is defined within the impl block for the Point struct:

impl Point {
    fn distance_from(&self, other: &Point) -> f64 {
        let dx = self.x - other.x;
        let dy = self.y - other.y;
        ((dx.pow(2) + dy.pow(2)) as f64).sqrt()
    }
}

Now, we can use this method for any Point instance:

let p1 = Point { x: 5, y: 10 };
let p2 = Point { x: 10, y: 12 };

println!("Distance: {}", p1.distance_from(&p2));

Associated Functions

Besides methods, you can define associated functions, which don’t act on a particular instance. For instance, consider a function that creates a point at the origin:

impl Point {
    fn origin() -> Point {
        Point { x: 0, y: 0 }
    }
}

You use associated functions like this:

let origin_point = Point::origin();

Mutability and Ownership

Rust emphasizes memory safety, hence the concepts of ownership and borrowing come into play when manipulating structs. You define mutability using the mut keyword, and it’s carried over from variable to struct fields. For instance:

let mut point = Point { x: 1, y: 2 };
point.x = 5;

Without mut, altering any fields within point will result in a compile-time error.

Conclusion

Defining structs along with methods in Rust is a way to encapsulate data and related behavior, much like objects in other object-oriented languages. By defining impl blocks, you can create methods and associated functions that either act on specific instances or provide functionalities across your type. This paradigm enhances code readability and maintainability, suitable for complex applications in Rust.

Next Article: Using Traits in Rust for Polymorphic Behavior

Previous Article: Understanding Encapsulation in Rust Without Traditional Classes

Series: Object-Oriented Programming in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior