DEV Community

Cover image for Rust Tips and Tricks #PartOne
Dan Mugisho M.
Dan Mugisho M.

Posted on • Updated on

Rust Tips and Tricks #PartOne

Rust is a programming language that has gained a reputation for its exceptional qualities in terms of reliability, speed, and overall enjoyment for the programmer. However, it is important to keep in mind that Rust is also recognized as a language with a relatively high level of complexity.

As programmers, when we start using a new language, we tend to apply the concepts and techniques we have learned from our previous language experiences. Initially, we may not be familiar with the idiomatic way of writing code, nor the efficient shortcuts that the new language offers. Nevertheless, we manage to make progress by experimenting with the code until it runs and compiles.

This is perfectly natural. Over time, by seeing other people’s code, we learn, we adapt, and we write better code. This post tries to speed up that process by showing you some of the Rust shorthands I have discovered so far.

Avoid unnecessary clones

When a variable is cloned using the .clone() method, its data is duplicated, which requires additional resources. As a result, clones typically have a detrimental impact on performance and should be used sparingly. In many cases, it is possible to pass references to the same variables to different functions, eliminating the need for cloning. For example :

Avoid unnecessary clones codesnap illustration

Using Cow as return type

Occasionally, you may need to write methods that accept a string slice (&str) as input and possibly return either an altered version of the input or the original string.

In such situations, the Cow type can prove to be useful since it allows you to avoid allocating new memory unnecessarily. By using Cow, you can modify the input string when needed, but if no changes are required, the original string can be returned without incurring any additional memory allocation costs.

Using Cow<str> codesnap illustration

Enum size is bounded by the largest member

To ensure that an Enum can accommodate its largest variant, its size is determined accordingly. To optimize memory usage, it is advisable to keep the variants within an Enum of similar sizes. However, if necessary, larger variants can be boxed. Consider this example :

Enum codesnap illustration

Using dbg!() macro instead of println!()

The dbg macro can be used to print the value as well as the source code of an express to stderr. Example usage:

dbg!() macro codesnap illustration

The above code will print :

2
[src/main.rs:5] var1 = 2
Output: [src/main.rs:6] var1 * 2 = 4
Enter fullscreen mode Exit fullscreen mode

Crossbeam channels instead of the standard ones

The crossbeam crate offers a powerful alternative to standard channels with support for the Select operation, timeouts, and more.

Crossbeam channels codesnap illustration

Customize and chain Panic handlers

Panic handlers (called hooks) can be overridden and chained, which becomes particularly useful when setting up custom error reporting and logging for your application.

Customize and chain Panic handlers codesnap illustration

Output :

custom error reporting logic panicked at 'test', src/main.rs:20:5
custom logging logic panicked at 'test', src/main.rs:20:5
Enter fullscreen mode Exit fullscreen mode

The standard swap function

The swap function allows you to directly swap two variables without needing to create a temporary variable.

The standard swap function codesnap illustration

Use impl Trait when working with Closures

When passing a closure to a function, it is generally better to use the “impl Fn/FnOnce/FnMut” approach instead of a generic one. This approach, also known as “impl Trait,” helps keep the function’s signature uncluttered. In more complex scenarios, however, you may need to box the closure with “Box” to make it work. It is essential to keep in mind that boxing a closure can introduce additional overhead, which may be undesirable in some cases.

Therefore, it is important to weigh the benefits and drawbacks of each approach and choose the one that best suits your requirements.

impl Trait with Closures codesnap illustration

Output :

setting up...
Action!
tearing down...
Enter fullscreen mode Exit fullscreen mode

Clippy and rustfmt

They are two of my favorite Rust tools. If you haven’t tried them yet, I highly recommend giving them a try. Clippy can detect various lints in your code and guide you towards writing more idiomatic code. To install Clippy, simply run rustup component add clippy, and to run it within your workspace, execute cargo clippy. For more details, visit Clippy’s GitHub repository.

Rustfmt is a tool that formats Rust code in compliance with style guidelines. Its name precisely reflects its purpose. To install rustfmt, you can run rustup component add rustfmt. Once installed, you can execute cargo fmt to format Rust code in your workspace. If you require further information, you can visit rustfmt’s GitHub repository.

Simplify Your Rust Error Handling with “thiserror” and “anyhow”

When it comes to handling errors in Rust, it is often best to use the “thiserror” and “anyhow” crates for an idiomatic approach. “Thiserror” is useful when the consumer of the error needs to take action based on specific error conditions.

CONCLUSION

Rust is a programming language with immense potential, and it has something new to offer every day. I hope that this post has provided you with valuable insights into Rust and helped you learn something new. If you have any questions or want to share your thoughts, please feel free to leave a comment or reach out to me. Let’s continue to explore the vast possibilities of Rust together.


☞ Follow me on Twitter & Linkedin

☞ Kindly subscribe for my upcoming articles

Top comments (1)

Collapse
 
derick1530 profile image
Derick Zihalirwa

Thank you for sharing 🙌