Traits 不能提供或要求结构字段。虽然有一个RFC (#1546) 允许在特征中使用字段。但是,没有任何不稳定的功能允许这样做(还没有?)。
不过,您仍然可以简化您正在尝试做的事情。我冒昧地重命名并更改了您的特征,以便能够提供更详尽的示例。
假设我们有一个Jobs 特征。其中定义了各种方法,都需要jobs: Vec<String> 字段。
trait Jobs {
fn add_job(&mut self, job: String);
fn clear_jobs(&mut self);
fn count_jobs(&self) -> usize;
}
使用宏
一种解决方案是使用macro,它实现了所有这些方法。
macro_rules! impl_jobs_with_field {
($($t:ty),+ $(,)?) => ($(
impl Jobs for $t {
fn add_job(&mut self, job: String) {
self.jobs.push(job);
}
fn clear_jobs(&mut self) {
self.jobs.clear();
}
fn count_jobs(&self) -> usize {
self.jobs.len()
}
}
)+)
}
然后您可以通过使用宏轻松地重用代码。
struct Person {
jobs: Vec<String>,
}
struct Customer {
jobs: Vec<String>,
}
impl_jobs_with_field!(Person);
impl_jobs_with_field!(Customer);
// or
impl_jobs_with_field!(Person, Customer);
使用第二个 HasJobs 特征
另一个解决方案可能是引入第二个 HasJobs 特征。然后,如果类型实现了HasJobs,则可以将blanket implementation 用于Jobs。
trait HasJobs {
fn jobs(&self) -> &[String];
fn jobs_mut(&mut self) -> &mut Vec<String>;
}
impl<T: HasJobs> Jobs for T {
fn add_job(&mut self, job: String) {
self.jobs_mut().push(job);
}
fn clear_jobs(&mut self) {
self.jobs_mut().clear();
}
fn count_jobs(&self) -> usize {
self.jobs().len()
}
}
现在HasJobs 仍然需要为您的所有类型实现。但是如果Jobs 有大量的方法。那么实现HasJobs就容易多了。我们也可以使用宏来做到这一点:
macro_rules! impl_has_jobs {
($($t:ty),+ $(,)?) => ($(
impl HasJobs for $t {
fn jobs(&self) -> &[String] {
&self.jobs
}
fn jobs_mut(&mut self) -> &mut Vec<String> {
&mut self.jobs
}
}
)+)
}
然后再一次,你只是这样做:
struct Person {
jobs: Vec<String>,
}
struct Customer {
jobs: Vec<String>,
}
impl_has_jobs!(Person);
impl_has_jobs!(Customer);
// or
impl_has_jobs!(Person, Customer);
使用Deref 和DerefMut
最后,如果Customer 始终是Person,那么您可以将Person 更改为struct 并使用组合,即将person: Person 添加到Customer(和其他类型)。
首先,impl Jobs for Person:
struct Person {
jobs: Vec<String>,
}
impl Jobs for Person {
fn add_job(&mut self, job: String) {
self.jobs.push(job);
}
fn clear_jobs(&mut self) {
self.jobs.clear();
}
fn count_jobs(&self) -> usize {
self.jobs.len()
}
}
那么现在您可以使用Deref 和DerefMut 将Customer 取消引用到Person。因此Person 的所有方法都可以直接通过Customer 获得。
然而,这个解决方案只有有效如果你只有一个“特征”,即你只能DerefCustomer到Person。你也不能Deref Customer 到SomethingElse。
use std::ops::{Deref, DerefMut};
struct Customer {
person: Person,
}
impl Deref for Customer {
type Target = Person;
fn deref(&self) -> &Self::Target {
&self.person
}
}
impl DerefMut for Customer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.person
}
}