我正在制作一个功能构建器,用于配置一个对象,例如:
struct Person
{
name: String,
position: String
}
当需要构造对象时,构建器本身会保留要应用于对象的盒装封闭列表:
struct FunctionalBuilder<TSubject>
where TSubject : Default
{
actions: Vec<Box<dyn Fn(&mut TSubject) -> ()>>
}
impl<TSubject> FunctionalBuilder<TSubject>
where TSubject : Default
{
fn build(self) -> TSubject
{
let mut subj = TSubject::default();
for action in self.actions
{
(*action)(&mut subj);
}
subj
}
}
The idea being that one can aggregate this builder and then customize it for an object such as Person
. Now, let's say I want to have a builder method called()
that takes a name and saves the assignment of the name in the closure. I implement it as follows:
impl PersonBuilder
{
pub fn called(mut self, name: &str) -> PersonBuilder
{
let value = name.to_string();
self.builder.actions.push(Box::new(move |x| {
x.name = value.clone();
}));
self
}
}
Is this the right way of doing things? Is there a better way that avoids the temporary variable and clone()
call?
完整的工作示例:
#[derive(Debug, Default)]
struct Person {
name: String,
position: String,
}
struct FunctionalBuilder<TSubject>
where
TSubject: Default,
{
actions: Vec<Box<dyn Fn(&mut TSubject) -> ()>>,
}
impl<TSubject> FunctionalBuilder<TSubject>
where
TSubject: Default,
{
fn build(self) -> TSubject {
let mut subj = TSubject::default();
for action in self.actions {
(*action)(&mut subj);
}
subj
}
fn new() -> FunctionalBuilder<TSubject> {
Self {
actions: Vec::new(),
}
}
}
struct PersonBuilder {
builder: FunctionalBuilder<Person>,
}
impl PersonBuilder {
pub fn new() -> Self {
PersonBuilder {
builder: FunctionalBuilder::<Person>::new(),
}
}
pub fn called(mut self, name: &str) -> PersonBuilder {
let value = name.to_string();
self.builder.actions.push(Box::new(move |x| {
x.name = value;
}));
self
}
pub fn build(self) -> Person {
self.builder.build()
}
}
pub fn main() {
let builder = PersonBuilder::new();
let me = builder.called("Dmitri").build();
println!("{:?}", me);
}
You already do it,
value
is own by your closure, the problem is that you requireFn
trait, this mean action (the function) need to be able to be call many time this meanvalue
need to be clone to keep it valid inside the closure. The closure can't give away its ownership.One way, would be to use
FnOnce
, this will make possible to remove the clone but this mean the builder can only be call once. Changeactions: Vec<Box<dyn FnOnce(&mut TSubject) -> ()>>,
andaction(&mut subj);
.更多: