rust 希望将参数化枚举传递给使用_作为参数的函数(如my_fun(MyEnum::Type(_)))

z4bn682m  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(167)

我有一个next_expected_kind方法,如果Iterable<Kind>的下一项是预期的类型,则返回它,否则返回一个错误。
对于Kind1这样的非参数化类型,它可以很好地工作,但是如果Kind2这样的类型需要参数,我不知道如何使用它。
类似于:

let _val = match s.next_expected_kind(Kind::Kind2(str)) {
    Ok(k) => str,
    _ => panic!("error"),
};

有没有什么取巧的办法?
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d21d5cff42fcca633e95b4915ce2bf1d

#[derive(PartialEq, Eq)]
enum Kind {
    Kind1,
    Kind2(String),
}

struct S {
    kinds: std::vec::IntoIter<Kind>,
}

impl S {
    fn next_expected_kind(&mut self, expected: Kind) -> Result<Kind, &str> {
        match self.kinds.next() {
            Some(k) if k == expected => Ok(k),
            _ => Err("not expected"),
        }
    }
}

fn main() {
    let mut s = S {
        kinds: vec![Kind::Kind1, Kind::Kind2(String::from("2"))].into_iter(),
    };
    _ = s.next_expected_kind(Kind::Kind1);

    // let _val = s.next_expected_kind(Kind::Kind2(str));
    let _val = match s.kinds.next() {
        Some(Kind::Kind2(str)) => str,
        _ => panic!("not expected"),
    };
}
xdnvmnnf

xdnvmnnf1#

您可以像这样使用std::mem::discriminant()

use std::mem::{Discriminant, discriminant};
#[derive(Debug, PartialEq, Eq)]
enum Kind {
    Kind1,
    Kind2(String),
}

struct S {
    kinds: std::vec::IntoIter<Kind>,
}

impl S {
    fn next_expected_kind(&mut self, expected: Discriminant<Kind>) -> Result<Kind, &str> {
        match self.kinds.next() {
            Some(k) if discriminant(&k) == expected => Ok(k),
            _ => Err("not expected"),
        }
    }
}

fn main() {
    let mut s = S {
        kinds: vec![Kind::Kind1, Kind::Kind2(String::from("2"))].into_iter(),
    };
    _ = dbg!(s.next_expected_kind(discriminant(&Kind::Kind1)));

    let _val = dbg!(s.next_expected_kind(discriminant(&Kind::Kind2(String::new()))));
}

一个明显的缺点是,无论在哪里调用,都必须创建一个带有“空”或默认数据的示例。
我能想到的唯一其他方法是编写一个宏,因为您不能只传递枚举的“变体”。

#[derive(Debug, PartialEq, Eq)]
enum Kind {
    Kind1(String),
    Kind2(i32, i32),
}

struct S {
    kinds: std::vec::IntoIter<Kind>,
}

macro_rules! next_expected_kind {
    ($self:expr, $expected:path) => {
        match $self.kinds.next() {
            Some(k) if matches!(k, $expected(..)) => Ok(k),
            _ => Err("not expected"),
        }
    }
}

fn main() {
    let mut s = S {
        kinds: vec![Kind::Kind1(String::from("1")), Kind::Kind2(2,3)].into_iter(),
    };
    _ = dbg!(next_expected_kind!(&mut s, Kind::Kind1));

    let _val = dbg!(next_expected_kind!(&mut s, Kind::Kind2));
}

注意:这有一个限制,所有的变体必须是元组变体或结构体变体,使用起来有点笨拙。

相关问题