Как уже упоминалось, Option
и Result
имеют тонн служебных методов на них.Кроме того, оператор try (?
) также можно использовать для чрезвычайно распространенного случая «вернуть ошибку или развернуть результат»
Я бы реализовал FromStr
для Face
и Suit
,Ваш код будет выглядеть следующим образом:
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 })
}
}
Если вы этого не сделали / не смогли, вы можете использовать существующие методы на Option
.Вы не определили Foo::from_usize
, поэтому я предполагаю, что возвращается Foo
, поэтому он будет использовать 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 })
}
Оба эти пути позволяют иметь полезных ошибки, такие как перечисление, которое позволяет узнать, был ли иск / лицо отсутствует / недействительным.Тип ошибки ()
бесполезен для потребителей.
Вы также можете определять Suit::from_char
и Face::from_char
и не пропускать реализацию массива.
Соединяя все это вместе:
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>
Это x.and_then(|y| y)
fn bind<A, B, F>(x: Option<A>, f: F) -> Option<B>
where
F: FnOnce(A) -> Option<B>,
Это 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>,
Это x.and_then(f).and_then(g)
См. Также: