如何使包含枚举变量的结构体具有枚举泛型性?

8
请看以下代码:
struct Human {
  name: String,
  profession: Profession,
}

enum Profession {
  Doctor,
  Teacher
}

struct Family {
  family_doctor: // How to express type that will mean Human (because name matters) of profession Doctor?
}

通过使Human成为通用类型,并将变体Doctor作为profession字段的类型参数传递,是否可以实现这一点?如果不行,那么您建议的最接近这种关系的解决方法是什么?

请注意,这个问题可能看起来像是一个旧问题的重复。但首先,Rust在不断发展,其次,我正在寻找一种解决方法。

1个回答

7

可能最简单的做法是将Profession作为特质(trait)而不是枚举(enum),并将每个Profession定义成一个单元结构体(unit struct):

struct Human<P: ?Sized + Profession> {
  name: String,
  profession: P,
}

struct Doctor;
struct Teacher;

trait Profession {}

impl Profession for Doctor {}
impl Profession for Teacher {}

struct Family {
  family_doctor: Human<Doctor>,
}

大多数接受人类参数的函数可以使用泛型或 impl Profession 实现:

fn into_name<P: Profession>(any_human: Human<P>) -> String {
    any_human.name
}

另一种编写接受不同类型的Human函数的方式是使用动态分派。如果您以这种方式进行操作,则必须通过指针来访问任何Human,例如Box<Human<dyn Profession>>&Human<dyn Profession>(请注意,在Human的定义中出现了P: ?Sized,因此可以执行此操作):

fn into_name_dyn(any_human: Box<Human<dyn Profession>>) -> String {
    any_human.name
}

另一个可能性是为Box<dyn Profession>实现 Profession,并将其用作类型参数。这将把指针放在Human内部,使得只有Profession被隐藏:

impl<P: ?Sized + Profession> Profession for Box<P> {}

fn into_name_box(any_human: Human<Box<dyn Profession>>) -> String {
    any_human.name
}

如果您仍然需要枚举类型 (enum),我有一个建议:将结构体放置在同名变体 (variants) 中。这样,当您为 Profession 特性增加行为时,可以通过延迟到内部类型的实现来为 SomeProfession 实现 Profession。使用 enum_derive 库可以使这个过程更容易。
enum SomeProfession {
    Doctor(Doctor),
    Teacher(Teacher),
}

impl Profession for SomeProfession {}

fn into_name_enum(any_human: Human<SomeProfession>) -> String {
    any_human.name
}

参见


1
这个解决方案意味着人类不能改变职业。 - Stargateur
1
哇,这是一个惊人的答案!最后一种方法完全让我明白了,而且看起来也很不错。话虽如此,为了解决我的原始问题,即字段重复,我更倾向于使用组合方法,将重复的字段放入结构体中。你的答案向我展示了有哪些选择,并让我做出了选择。 - Nurbol Alpysbayev
1
在最后一个例子中,“Human”指的是什么? - Maximilian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接