Ric*_*eak 4 default private public rust
当我进行此类设置时,我收到错误:
默认_测试.rs:
mod default_mod;
use default_mod::Point;
fn main() {
let _p1 = Point::new();
let _p2: Point = Point {
z: 1,
..Default::default()
};
}
Run Code Online (Sandbox Code Playgroud)
默认_mod.rs:
pub struct Point {
x: i32,
y: i32,
pub z: i32,
}
impl Point {
pub fn new() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
impl Default for Point {
fn default() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
Run Code Online (Sandbox Code Playgroud)
这给出了编译器错误:
default_test.rs:9:7
|
9 | ..Default::default()
| ^^^^^^^^^^^^^^^^^^ field `x` is private
error[E0451]: field `y` of struct `default_mod::Point` is private
Run Code Online (Sandbox Code Playgroud)
简短版本-我有一个包含公共和私有字段的结构。我想用默认值初始化这个结构,但有时会覆盖它们。
我似乎无法修复这个错误,也没有在互联网或文档上看到任何提到这样的错误的内容。
这让我感到惊讶,因为我认为一个常见的用例是初始化一个结构,并且该结构的某些成员将是私有的,因此您可以隐藏后面的实现细节和接口。
就我而言,私有字段是 aVec因为我有一些逻辑需要在向量中添加或删除内容,所以我想将其设为私有以防止任何人弄乱数据结构。
我在这里有什么选择?
这让我感到惊讶,因为我认为一个常见的用例是初始化一个结构,并且该结构的某些成员将是私有的,因此您可以隐藏后面的实现细节和接口。
问题在于结构更新语法并不像您想象的那样。例如,书中展示了以下代码:
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
};
Run Code Online (Sandbox Code Playgroud)
该..user1语法填充User我们没有明确指定的字段,例如active: user1.active, signin_count: user1.signin_count. ..后面可以跟一个任意表达式,该表达式返回结构,这就是发挥作用的地方,并且含义与预期的aDefault::default()相同。然而,脱糖保持不变,归结为分配各个字段,在任何情况下都不会授予对私有字段的特殊访问权限。User::default()User
回到你的例子,这段代码:
let p = Point {
z: 1,
..Default::default()
};
Run Code Online (Sandbox Code Playgroud)
是语法糖:
let p = {
let _tmp = Point::default();
Point {
x: _tmp.x, // assigning private field
y: _tmp.y, // assigning private field
z: 1,
}
};
Run Code Online (Sandbox Code Playgroud)
而不是预期的:
// NOT what happens
let p = {
let _tmp = Point::default();
p.z = 1; // no private assignment
_tmp
};
Run Code Online (Sandbox Code Playgroud)
我在这里有什么选择?
最惯用的选择是提供一个构建器Point。这也有点庞大1,因此如果您正在寻找一个简单的解决方案,您也可以手动使用Point::default()和设置该z属性。结构更新语法与具有私有字段的结构不兼容,并且对您的类型没有用处。
1 尽管有像derive_builder、typed-builder和builder-pattern这样的包可以减轻一些苦差事。