gpt4 book ai didi

rust - 具有默认实现和所需结构成员的特性

转载 作者:行者123 更新时间:2023-12-03 11:25:34 26 4
gpt4 key购买 nike

我有一个 rust 特征,它应该为向量添加一个值。为了add_job要使函数正常工作,必须确保在为具体结构实现特征时向量存在。
以下代码当然失败了,因为从未实现过作业。它只是为了证明我的意图:

trait Person {
// default implementation of add job
fn add_job(&self, job: String) {
self.jobs.push(job)
}
}

struct Customer {
// add_job is used as default implementation
// provided by trait
}

impl Person for Customer {
// some stuff
}

fn main() {
let mut george = Customer {};
george.add_job("programmer".to_string());
}
有没有办法让特征也提供结构成员?
可能不是,但是解决上述问题的“使用rust ”方法是什么?

最佳答案

Traits 不能提供或要求结构字段。虽然有一个 RFC (#1546)关于在特征中允许字段。但是,没有任何不稳定的功能允许这样做(还?)。

不过,您仍然可以简化您正在尝试做的事情。我冒昧地重命名和更改您的特征,以便能够提供更全面的示例。
假设我们有一个 Jobs特征。其中定义了各种方法,都需要 jobs: Vec<String> field 。

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特征。然后你可以使用 blanket implementationJobs如果类型实现 HasJobs .
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);

使用 DerefDerefMut最后,如果 Customer始终是 Person ,那么你可以更改 Personstruct并使用组合,即添加 person: PersonCustomer (和其他类型)。
首先, 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 取消引用 CustomerPerson .因此所有 Person的方法可直接通过 Customer 获得.
但是,此解决方案仅在您只有一个“特征”时才有效,即您只能 Deref CustomerPerson .你也不能 Deref CustomerSomethingElse .
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
}
}

关于rust - 具有默认实现和所需结构成员的特性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65380698/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com