这是按值捕获字符串的正确方法吗?
Is this the right way to capture a string by value?
我正在制作一个功能构建器来配置一个对象,例如:
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
}
}
想法是可以聚合此构建器,然后针对 Person
等对象对其进行自定义。现在,假设我想要一个构建器方法 called()
,它接受一个名称并将名称的分配保存在闭包中。我是这样实现的:
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
}
}
这是正确的做事方式吗?有没有更好的方法来避免临时变量和 clone()
调用?
完整的工作示例:
#[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);
}
你已经做到了,value
属于你的闭包,问题是你需要 Fn
特性。这意味着 action
(函数)需要能够被多次调用。这意味着需要克隆 value
以使其在闭包内有效。闭包不能放弃它的所有权。
一种方法是使用 FnOnce
,这样可以删除 clone
,但这意味着构建器只能使用一次。为此,请使用 actions: Vec<Box<dyn FnOnce(&mut TSubject) -> ()>>,
和 action(&mut subj);
.
更多:
我正在制作一个功能构建器来配置一个对象,例如:
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
}
}
想法是可以聚合此构建器,然后针对 Person
等对象对其进行自定义。现在,假设我想要一个构建器方法 called()
,它接受一个名称并将名称的分配保存在闭包中。我是这样实现的:
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
}
}
这是正确的做事方式吗?有没有更好的方法来避免临时变量和 clone()
调用?
完整的工作示例:
#[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);
}
你已经做到了,value
属于你的闭包,问题是你需要 Fn
特性。这意味着 action
(函数)需要能够被多次调用。这意味着需要克隆 value
以使其在闭包内有效。闭包不能放弃它的所有权。
一种方法是使用 FnOnce
,这样可以删除 clone
,但这意味着构建器只能使用一次。为此,请使用 actions: Vec<Box<dyn FnOnce(&mut TSubject) -> ()>>,
和 action(&mut subj);
.
更多: