为什么我必须匹配/破坏通用枚举的非通用变量?

问题描述 投票:0回答:1

我有一个通用枚举,其中只有一个变体使用通用类型。当将ParseResult<T>“转换”为ParseResult<U>时,编译器也迫使我破坏非通用部分。

但是非通用部分会立即以完全相同的方式重新组装并返回。没有代码重复,没有更聪明/更优雅的解决方案吗?

#[derive(PartialEq, Debug)]
enum ParseResult<'a, T> {
    Success(T, &'a str),
    Failure(&'static str),
}

fn char<'a>(c: char) -> impl Fn(&'a str) -> ParseResult<'a, char> {
    move |input| match input.chars().next() {
        Some(candidate) if c == candidate => ParseResult::Success(candidate, &input[1..]),
        Some(_) => ParseResult::Failure("chars didn't match"),
        None => ParseResult::Failure("unexpected end of stream"),
    }
}

fn or<'a, T>(
    mut lhs: impl FnMut(&'a str) -> ParseResult<T>,
    mut rhs: impl FnMut(&'a str) -> ParseResult<T>,
) -> impl FnMut(&'a str) -> ParseResult<T> {
    move |input| match lhs(input) {
        ParseResult::Failure(_) => rhs(input),
        ok => ok,
    }
}

fn and<'a, T, U>(
    mut lhs: impl FnMut(&'a str) -> ParseResult<T>,
    mut rhs: impl FnMut(&'a str) -> ParseResult<U>,
) -> impl FnMut(&'a str) -> ParseResult<(T, U)> {
    move |input| match lhs(input) {
        ParseResult::Success(left, after) => match rhs(after) {
            ParseResult::Success(right, after) => ParseResult::Success((left, right), after),
            // Only explicit works:
            ParseResult::Failure(why) => ParseResult::Failure(why),
        },
        // Same as line as above, same goes here.
        ParseResult::Failure(why) => ParseResult::Failure(why),
    }
}

不是最后两条线::Failure无效的事情:

  1. [bad => bad,预期元组,找到类型参数U
  2. bad => bad as ParseResult<(T, U)>,
  3. [bad @ ParseResult::Failure(why) => bad,预期元组,找到类型参数U

Playground

generics types enums rust variant
1个回答
0
投票

但是非通用部分会立即以完全相同的方式重新组装并返回。没有代码重复,没有更聪明/更优雅的解决方案吗?

似乎以相同的方式重新组装,但这不是因为它的类型从ParseResult<T>更改为ParseResult<U>(在您的情况下为ParseResult<(T,U)>)。它们的大小不同,因此ParseResult<T>::Failed(err)ParseResult<U>::Failed(err)不同。

如果我们查看标准库如何处理此问题:https://doc.rust-lang.org/src/core/result.rs.html#517-522

您可以看到使用了相同的模式:

match self {
     Ok(t) => Ok(op(t)),
     Err(e) => Err(e),
}
© www.soinside.com 2019 - 2024. All rights reserved.