如何在Rust中将一个结构体映射到另一个结构体?

6

在其他编程语言(如Java)中,可以使用库将对象字段映射到另一个对象(例如mapstruct)。这对于隔离控制器和服务确实非常有用。

PersonDto personDto = mapper.businessToDto(personBusiness);

我找不到用Rust语言如何做这件事情的方法?我没有发现任何有帮助的库或者任何可行的方法。非常感谢任何提供相关资源的人!


1
Rust不是真正的面向对象编程(至少不是非常严谨的Java意义上),所以这甚至可能没有意义。特别是,我们拥有traits似乎使得像mapstruct这样的东西变得不必要。 - mcarton
是的,Mapstruct 只是有助于避免繁琐的手动映射。特质如何使结构映射不那么乏味? - bachrc
从问题中,我期望映射函数是手动编写的,但是在您的评论中,您提到避免繁琐的手动映射:您是在寻找手动还是自动映射函数? - Matthieu M.
确实,我问了一些超出最初问题范围的内容。我是为了获取更多信息而提出这个问题的。 - bachrc
如果您不想手动编写实际的映射,而是依赖于一些注释和/或约定,则可以使用proc-macro。没有一个能够掌控它们所有的proc-macro库,但有一些非常常见的库。然而,我认为这种用例在Rust中并不常见。 - mcarton
2个回答

20
在Rust中,通常使用From trait来实现。该trait用于将一种类型转换为另一种类型。
struct Person {
  name: String,
  age: u8,
}

struct PersonDto {
  name: String,
  age: u64,
}

impl From<Person> for PersonDto {
  fn from(p: Person) -> Self {
    Self {
      name: p.name,
      age: p.age.into(),
    }
  }
}

所以你可以进行 Into 转换:

let person = Person { name: "Alex".to_string(), age: 42 };

let person_dto: PersonDto = person.into();
// or via an explicit `T::from:
let person_dto = PersonDto::from(person);

0
在评论中,问题的作者提到了“避免繁琐的手动映射”作为他们问题的一部分。Rust crate o2o(我是作者)专门尝试解决这个问题。
struct Person {
  name: String,
  age: u8,
}

#[derive(o2o)]
#[o2o(from_owned(Person))]
struct PersonDto {
  name: String,
  #[o2o(as_type(u8))]
  age: u64,
}

这将自动生成以下代码:
impl std::convert::From<Person> for PersonDto {
    fn from(value: Person) -> PersonDto {
        PersonDto {
            name: value.name,
            age: value.age as u64,
        }
    }
}

它可以为结构体、元组结构体、元组生成FromInto和自定义IntoExisting特征的实现,并且可以处理字段名称、类型不匹配、跳过字段、嵌套结构体、嵌套集合、'不平衡'结构体、包装结构体等情况。它还被设计为适用于映射的任何一侧。

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