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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.66.128