#枚举 #三路 #Haskell #捕获 # #错误 #hackage

这些

一种三路枚举捕获 This、That 或 Both。灵感来源于 Haskell 包 https://hackage.haskell.org/package/these

5 个版本 (3 个稳定版本)

2.0.0 2020 年 11 月 11 日
1.1.0 2020 年 11 月 11 日
1.0.0 2019 年 9 月 18 日
0.1.1 2019 年 9 月 8 日
0.1.0 2019 年 9 月 8 日

Rust 模式 中排名第 1578

每月下载量 35

GPL-3.0 或更高版本

27KB
204

These

These 表示数据的 3 分支。可以将其视为 Result,只是我们有一个额外的情形可以同时包含结果 T 和错误 E。这在我们可以继续计算最终结果但同时也遇到错误时很有用。

enum These<T, U> {
    This(T),
    That(U),
    Both(T, U)
}

我们有三个构造函数 This 保留 TThat 保留 U,和 Both 保留两者。

这里和那里

如果我们想讨论所有 T,我们使用术语 Here。这意味着我们可能有一个 ThisBoth。或者在代码中

use these::These;

fn is_here<T: Copy, U: Copy>(these: &These<T, U>) -> bool {
    these.is_this() || these.is_these()
}

如果我们想讨论所有 U,我们使用术语 There。这意味着我们可能有一个 ThatBoth。或者在代码中

use these::These;

fn is_here<T: Copy, U: Copy>(these: These<T, U>) -> bool {
    these.is_that() || these.is_these()
}

构造示例

假设我们有一个只允许小于 10 的数字的函数。我们公开一个新类型 LessThanTen,并期望我们的用户使用 is_less_than_ten 来验证 i8 到这个类型。我们可以使用 Result 并对此进行建模

#[derive(Debug, PartialEq)]
struct LessThanTen(i8);

#[derive(Debug, PartialEq)]
pub enum Error {
    IsGreaterThanOrEqualToTen,
}

pub fn is_less_than_ten(i: i8) -> Result<LessThanTen, Error> {
    if i < 10 {
        Ok(LessThanTen(i))
    } else {
        Err(Error::IsGreaterThanOrEqualToTen)
    }
}

assert_eq!(is_less_than_ten(8), Ok(LessThanTen(8)));
assert_eq!(is_less_than_ten(10), Err(Error::IsGreaterThanOrEqualToTen));

但过了一段时间,我们意识到我们可以开始支持所有小于20的数字。我们可以采取类似的方法,但希望保持向后兼容,并且跟踪遇到大于10的数字的情况。也许我们想要对这些错误进行统计,或者将成功的结果转换为LessThanTen以保持向后兼容。我们可以使用These来解决此问题,并可以按照以下方式建模

use these::These;

#[derive(Debug, PartialEq)]
struct LessThanTen(i8);

#[derive(Debug, PartialEq)]
struct LessThanTwenty(i8);

#[derive(Debug, PartialEq)]
pub enum Error {
    IsGreaterThanOrEqualToTen,
    IsGreaterThanOrEqualToTwenty,
}

pub fn is_less_than_ten(i: i8) -> Result<LessThanTen, Error> {
    if i < 10 {
        Ok(LessThanTen(i))
    } else {
        Err(Error::IsGreaterThanOrEqualToTen)
    }
}

pub fn is_less_than_twenty(i: i8) -> These<Error, LessThanTwenty> {
    if i < 10 {
        These::That(LessThanTwenty(i))
    } else if i < 20 {
        These::Both(Error::IsGreaterThanOrEqualToTen, LessThanTwenty(i))
    } else {
        These::This(Error::IsGreaterThanOrEqualToTwenty)
    }
}

// Convert to the backwards compatible scenario
pub fn backwards_compatible(r: These<Error, LessThanTwenty>) -> Result<LessThanTen, Error> {
    r.collapse_these(
        |e| Err(e),
        |LessThanTwenty(i)| Ok(LessThanTen(i)),
        |e, _| Err(e),
    )
}

assert_eq!(is_less_than_ten(8), Ok(LessThanTen(8)));
assert_eq!(is_less_than_ten(10), Err(Error::IsGreaterThanOrEqualToTen));
assert_eq!(is_less_than_twenty(8), These::That(LessThanTwenty(8)));
assert_eq!(is_less_than_twenty(10), These::Both(Error::IsGreaterThanOrEqualToTen, LessThanTwenty(10)));
assert_eq!(is_less_than_twenty(20), These::This(Error::IsGreaterThanOrEqualToTwenty));

assert_eq!(backwards_compatible(is_less_than_twenty(8)), Ok(LessThanTen(8)));

无运行时依赖