There are three struct forms: unit structs, tuple structs, and named field structs:
struct UnitStruct;
struct TupleStruct(String, usize);
struct NamedStruct { string: String, is_cuss_word: bool }unit structs are uncommon; they can't hold any data, and are only used in certain special circumstances; you can ignore them for now.
tuple structs provide access to their contents by indexing: in I only like to use them when they at most two members, and in 90% of cases where I have two fields, I use names:
let my_tup = TupleStruct(String::from("hello"), 42);
assert_eq!(my_tup.0, String::from("hello"));
assert_eq!(my_tup.1, 42));named structs are great, and you should use them most of the time.
The From trait looks like this:
pub trait From<T> {
fn from(_: T) -> Self;
}This trait can be implemented to perform simple conversions between types.
struct Secret(String);
impl From<String> for Secret {
fn from(inp: String) -> Secret {
Secret(inp)
}
}
let secret_string = String::from("kryptonite seven craton optimist");
let secret = Secret::from(secret_string); // well that looks familiar...One very cool thing about From is its relationship with Into. Basically: If you impl From<T> for U, you get impl Into<U> for T for free. This means we can now do this:
let secret_string = String::from("kryptonite seven craton optimist");
let secret: Secret = secret_string.into();More helpfully, rust's type inference means you can do things like this:
fn make_secret(input: String) -> Secret {
s.into()
}Because the return value of the function is a Secret, Rust can infer what into we're looking for.
All types implement From<Self>, for free. This is useful for writing generic functions can take either the expected type or any type that can be into()'d it. For instance,
fn process_secret<S: Into<Secret>>(input: s) {
let secret = input.into();
// do some secret stuff
}From and Into are particularly useful when working with strings. Suppose we want to be able to construct our Secret type with either a String or a &str:
impl<T> From<T> for Secret where T: Into<String> {
fn from(s: T) -> Secret {
Secret(s.into())
}
}
let secret_string: Secret = String::from("kryptonite seven craton optimist").into();
let secret_str: Secret = "carnival uptown gamine idiolect".into();