As mentioned, Option
and Result
have tons of utility methods on them. Additionally, the try operator (?
) can also be used for the extremely common case of "return the failure or unwrap the result"
I'd implement FromStr
for Face
and Suit
. Your code would then look like:
impl FromStr for Card {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let face = s[0..1].parse()?;
let suit = s[1..2].parse()?;
Ok(Card { face, suit })
}
}
If you didn't / couldn't, you can use the existing methods on Option
. You didn't define Foo::from_usize
, so I assume to returns Foo
, so it would use map
:
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut c = s.chars();
let face = c
.next()
.and_then(|c| FACES.find(c))
.map(Face::from_usize)
.ok_or(())?;
let suit = c
.next()
.and_then(|c| SUITS.find(c))
.map(Suit::from_usize)
.ok_or(())?;
Ok(Card { face, suit })
}
Both of these paths allow you to have useful errors, such as an enum that lets you know if the suit / face was missing / invalid. An error type of ()
is useless to consumers.
You could also define Suit::from_char
and Face::from_char
and not leak the implementation of the array out.
Putting it all together:
impl Suit {
fn from_char(c: char) -> Option<Self> {
use Suit::*;
[('c', C), ('d', D), ('h', H), ('s', S)]
.iter()
.cloned()
.find(|&(cc, _)| cc == c)
.map(|(_, s)| s)
}
}
enum Error {
MissingFace,
MissingSuit,
InvalidFace,
InvalidSuit,
}
impl FromStr for Card {
type Err = Error;
fn from_str(x: &str) -> Result<Self, Self::Err> {
use Error::*;
let mut xs = x.chars();
let face = xs.next().ok_or(MissingFace)?;
let face = Face::from_char(face).ok_or(InvalidFace)?;
let suit = xs.next().ok_or(MissingSuit)?;
let suit = Suit::from_char(suit).ok_or(InvalidSuit)?;
Ok(Card { face, suit })
}
}
fn join<T>(x: Option<Option<T>>) -> Option<T>
This is x.and_then(|y| y)
fn bind<A, B, F>(x: Option<A>, f: F) -> Option<B>
where
F: FnOnce(A) -> Option<B>,
This is x.and_then(f)
fn chain<A, B, C, F, G>(x: Option<A>, f: F, g: G) -> Option<C>
where
F: FnOnce(A) -> Option<B>,
G: FnOnce(B) -> Option<C>,
This is x.and_then(f).and_then(g)
See also: