Unlock Your Python Backend Career: Build 30 Projects in 30 Days. Join now for just $54

Chapter 2: Advanced Rust Concepts

Chapter 2: Advanced Rust Concepts

Structs, Enums, and Methods

Structs, Enums, and Methods

At this point, you’ll see that there are two ways we call methods:

  1. type.method(): This is for instance methods – methods bound to a specific instance of the type.

  2. type::method(): This is for static methods – methods that are bound to the type itself and do not need self(the instance reference) as a parameter.

As mentioned earlier, Rust uses Structs and Enums for data abstractions. A struct is represented syntactically like so:

struct User {
	username: String,
	first_name: String,
}

And then methods for this struct is done with the impl keyword:

impl User {
  fn new(username: String, first_name: String) → User {
   User {
	username,
	first_name
	}
}

 fn say_name(&self) → {
   println!(“{} name is {}”, self.username, self.first_name);
 }
}

As you can guess, new is a static method, while say_name is an instance method.

Enums on the other hand are used to group similar structs under an abstraction.

For example, if we wanted to extend the User struct to contain a gender field, we could implement a gender structs like so:

struct Male {
	symbol: u8,
}

struct Female {
	symbol: u8,
}

and then group them under a gender enum like so:

enum Gender {
	Female,
	Male,
}

Our User struct can then make use of this abstraction like so:

struct User {
	username: String,
	first_name: String,
	gender: Gender,
}

Accessing structs associated with an enum is done with the :: operator.

Going back to the Ordering Code above, we can see that Ordering is an enum with struct types: Less, Greater, and Equal.

When the comparison is done with the cmp method, the method yields one of these types, we can then take advantage of the graceful match syntax to perform our calculations based on these types:

Ordering::Less => {
	((name1_count as f32 / name2_count as f32) as f32 * 100.0) as f32
},
Ordering::Greater => {
	((name2_count as f32 / name1_count as f32) as f32 * 100.0) as f32
},
Ordering::Equal => {
	50.0
}

Since we’ll be working with fractions here, it’s important to switch data types to floating values in order to maintain precision.

This is done using the as keyword. We have to cast all values into the f32 type before our code works successfully.

For the Equal arm, we also have to make 50 as a floating-point value to match the return type. It’s easy to miss.

Return value(match)

Since we have one-liner operations as a resolved value, we do not need the return keyword. The values would be returned implicitly due to the lack of a semicolon as a delimiter.

Back to main(the end?)

We can head back to the main function and call the calculate_compatibility function and display the results:

let compat_value = calculate_compatibility(name1_count, name2_count).floor();
    
println!("Love compatibility between {} and {} is {}%", name1.trim(), name2.trim(), compat_value);

The trim method removes whitespace characters at the beginning and end of the string.

Whenever you're ready

There are 4 ways we can help you become a great backend engineer:

The MB Platform

Join 1000+ backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.

The MB Academy

The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

Join Backend Weekly

If you like post like this, you will absolutely enjoy our exclusive weekly newsletter, Sharing exclusive backend engineering resources to help you become a great Backend Engineer.

Get Backend Jobs

Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board