[英]Why does Rust's documentation for methods use a separate builder struct as an example?
I was going through the struct and method docs and was wondering why the docs use this example: 我正在浏览结构和方法文档 ,并想知道为什么文档使用这个例子:
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
struct CircleBuilder {
x: f64,
y: f64,
radius: f64,
}
impl CircleBuilder {
fn new() -> CircleBuilder {
CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, }
}
fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.y = coordinate;
self
}
fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
self.radius = radius;
self
}
fn finalize(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius }
}
}
fn main() {
let c = CircleBuilder::new()
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
println!("area: {}", c.area());
println!("x: {}", c.x);
println!("y: {}", c.y);
}
My slightly modified code is smaller and appears to do the exact same thing: 我稍微修改过的代码较小,看起来完全一样:
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn new() -> Circle {
Circle { x: 0.0, y: 0.0, radius: 1.0, }
}
fn x(&mut self, coordinate: f64) -> &mut Circle {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut Circle {
self.y = coordinate;
self
}
fn radius(&mut self, radius: f64) -> &mut Circle {
self.radius = radius;
self
}
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
fn finalize(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius }
}
}
fn main() {
let c = Circle::new()
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
println!("area: {}", c.area());
println!("x: {}", c.x);
println!("y: {}", c.y);
}
In general, a Circle
and a CircleBuilder
are not the same thing, so it makes sense to treat them as different types. 一般来说,
Circle
和CircleBuilder
不是一回事,因此将它们视为不同类型是有意义的。 In your example, once a Circle
has been "finalized", there's actually nothing stopping someone from calling the builder methods ( x
, y
, radius
) - there's nothing enforcing it. 在你的例子中,一旦
Circle
被“敲定”,实际上没有什么能阻止某人调用构建器方法( x
, y
, radius
) - 没有什么可以强制执行它。 It may also be unclear to users which methods are for building, and which are for use on a constructed object. 用户还可能不清楚哪种方法用于构建,哪些方法用于构造的对象。 Rust has a type system which can be used to statically avoid mistakes like this - it makes sense to use it!
Rust有一个类型系统,可以用来静态避免这样的错误 - 使用它是有道理的!
In other cases, the finalize step may be less trivial - eg opening files, doing other I/O, or calculating some other private fields (which wouldn't make sense to initialise when constructing the builder). 在其他情况下,最终化步骤可能不那么简单 - 例如打开文件,执行其他I / O或计算其他一些私有字段(在构建构建器时初始化是没有意义的)。
Note that the CircleBuilder
impl contains only methods that can be chained together (they return a &mut CircleBuilder
), one that initializes and one that returns a Circle
. 请注意,
CircleBuilder
impl仅包含可以链接在一起的方法(它们返回一个&mut CircleBuilder
),一个初始化,一个返回一个Circle
。
It makes sense when someone wants to create an object "incrementally", through multiple steps, and separate those methods from eg those exposing the object's properties. 当有人想要通过多个步骤“递增地”创建对象并将这些方法与例如暴露对象属性的方法分开时,这是有道理的。
Your code is fine - it's a matter of preference. 你的代码很好 - 这是一个偏好的问题。 I would probably only create a
new(x: f64, y: f64, radius: f64)
method that would build a full Circle
at once, like Circle::new(1.0, 2.0, 2.0)
. 我可能只会创建一个
new(x: f64, y: f64, radius: f64)
方法,它会立即构建一个完整的Circle
,如Circle::new(1.0, 2.0, 2.0)
new(x: f64, y: f64, radius: f64)
Circle::new(1.0, 2.0, 2.0)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.