从同一个构建器构建多个值是否有益?
- 如果是,请使用
&mut self
- 如果没有,请使用
self
考虑std::thread::Builder https://doc.rust-lang.org/std/thread/struct.Builder.html这是一个建设者std::thread::Thread https://doc.rust-lang.org/std/thread/struct.Thread.html。它用Option
内部字段用于配置如何构建线程:
pub struct Builder {
name: Option<String>,
stack_size: Option<usize>,
}
It uses self
to .spawn()
线程,因为它需要所有权name
。理论上可以使用&mut self
and .take()
名称超出字段,但随后调用.spawn()
不会产生相同的结果,这是一个糟糕的设计。它可以选择.clone()
名称,但是生成线程会产生额外的且通常不需要的成本。使用&mut self
将是一种损害。
考虑std::process::Command https://doc.rust-lang.org/std/process/struct.Command.html它作为一个建设者std::process::Child https://doc.rust-lang.org/std/process/struct.Child.html。它的字段包含程序、参数、环境和管道配置:
pub struct Command {
program: CString,
args: Vec<CString>,
env: CommandEnv,
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
// ...
}
It uses &mut self
to .spawn()
因为它确实not拥有这些领域的所有权来创建Child
。无论如何,它必须在内部将所有数据复制到操作系统,因此没有理由消耗self
。使用相同的配置生成多个子进程还有一个切实的好处和用例。
考虑std::fs::OpenOptions https://doc.rust-lang.org/std/fs/struct.OpenOptions.html它作为一个建设者std::fs::File https://doc.rust-lang.org/std/fs/struct.File.html。它只存储基本配置:
pub struct OpenOptions {
read: bool,
write: bool,
append: bool,
truncate: bool,
create: bool,
create_new: bool,
// ...
}
It uses &mut self
to .open()
因为它不需要任何东西的所有权就可以工作。它有点类似于线程构建器,因为有一个与文件关联的路径,就像有一个与线程关联的名称一样,但是,文件路径仅传递给.open()
并且不与构建器一起存储。有一个使用相同配置打开多个文件的用例。
上面的考虑实际上只涵盖了语义self
in the .build()
方法,但有足够的理由表明,如果您选择一种方法,您也应该将其用于临时方法:
- API一致性
- 链接
(&mut self) -> &mut Self
into build(self)
显然不会编译
- using
(self) -> Self
into build(&mut self)
会限制构建器长期重用的灵活性
也可以看看:如何在 Rust 中使用链式方法调用编写惯用的构建模式? https://stackoverflow.com/questions/41617182