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();