Book Image

Rust Standard Library Cookbook

By : Jan Hohenheim, Daniel Durante
Book Image

Rust Standard Library Cookbook

By: Jan Hohenheim, Daniel Durante

Overview of this book

Mozilla’s Rust is gaining much attention with amazing features and a powerful library. This book will take you through varied recipes to teach you how to leverage the Standard library to implement efficient solutions. The book begins with a brief look at the basic modules of the Standard library and collections. From here, the recipes will cover packages that support file/directory handling and interaction through parsing. You will learn about packages related to advanced data structures, error handling, and networking. You will also learn to work with futures and experimental nightly features. The book also covers the most relevant external crates in Rust. By the end of the book, you will be proficient at using the Rust Standard library.
Table of Contents (12 chapters)

There's more...

You might have noticed that for our example we really didn't need a length member and could have just calculated a length whenever we print. We use this pattern anyway, to illustrate the point of its usefulness in hiding implementations. Another good use for it is when the members of a struct themselves have their own constructors and one needs to cascade the constructor calls. This happens, for example, when we have a Vec as a member, as we will see later in the book, in the, Using a vector section in Chapter 2, Working with Collections.

Sometimes, your structs might need more than one way to initialize themselves. When this happens, try to still provide a new() method as your default way of construction and name the other options according to how they differ from the default. A good example of this is again vector, which not only provides a Vec::new() constructor but also a Vec::with_capacity(10), which initializes it with enough space for 10 items. More on that again in the Using a vector section in Chapter 2, Working with Collections.

When accepting a kind of string (either &str, that is, a borrowed string slice, or String, that is, an owned string) with plans to store it in your struct, like we do in our example, also considering a Cow. No, not the big milk animal friends. A Cow in Rust is a Clone On Write wrapper around a type, which means that it will try to borrow a type for as long as possible and only make an owned clone of the data when absolutely necessary, which happens at the first mutation. The practical effect of this is that, if we rewrote our NameLength struct in the following way, it would not care whether the called passed a &str or a String to it, and would instead try to work in the most efficient way possible:

use std::borrow::Cow;
struct NameLength<'a> {
name: Cow<'a, str>,
length: usize,
}

impl<'a> NameLength<'a> {
// The user doesn't need to setup length
// We do it for him!
fn new<S>(name: S) -> Self
where
S: Into<Cow<'a, str>>,
{
let name: Cow<'a, str> = name.into();
NameLength {
length: name.len(),
name,
}
}

fn print(&self) {
println!(
"The name '{}' is '{}' characters long",
self.name, self.length
);
}
}

If you want to read more about Cow, check out this easy-to-understand blog post by Joe Wilm: https://jwilm.io/blog/from-str-to-cow/.

The Into trait used in the Cow code is going to be explained in the Converting types into each other section in Chapter 5, Advanced Data Structures.