Rust impl 带有私有字段的默认特征

问题描述 投票:0回答:2

当我进行这种设置时,我收到错误:

default_test.rs:

mod default_mod;

use default_mod::Point;

fn main() {
    let _p1 = Point::new();
    let _p2: Point = Point {
        z: 1,
        ..Default::default()
    };
}

default_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 }
    }
}

这会给出编译器错误:

default_test.rs:9:7
  |
9 |     ..Default::default()
  |       ^^^^^^^^^^^^^^^^^^ field `x` is private

error[E0451]: field `y` of struct `default_mod::Point` is private

简短版本 - 我有一个包含公共和私有字段的结构。我想用默认值初始化这个结构,但有时会覆盖它们。

我似乎无法修复此错误,也没有在互联网或文档上看到任何内容,甚至提到了这样的错误。

这让我感到惊讶,因为我认为常见的用例是初始化一个结构,并且该结构的某些成员将是私有的,因此您可以隐藏背后的实现细节和接口。

在我的例子中,私有字段是一个

Vec
,因为我有一些逻辑需要在向量中添加或删除内容,所以我想将其设为私有以防止任何人弄乱数据结构。

我有什么选择?

rust default private public
2个回答
6
投票

这让我感到惊讶,因为我认为常见的用例是初始化一个结构,并且该结构的某些成员将是私有的,因此您可以隐藏背后的实现细节和接口。

问题在于结构更新语法并不像你想象的那样。例如,显示了以下代码:

let user2 = User {
    email: String::from("[email protected]"),
    username: String::from("anotherusername567"),
    ..user1
};

..user1
语法填充了我们未明确指定的
User
字段,例如
active: user1.active, signin_count: user1.signin_count
..
后面可以跟一个返回结构的任意表达式,这就是
Default::default()
发挥作用的地方,并且与
User::default()
的含义相同,因为需要
User
。然而,脱糖保持不变,归结为分配各个字段,在任何情况下都不会授予对私有字段的特殊访问权限。

回到你的例子,这段代码:

let p = Point {
    z: 1,
    ..Default::default()
};

是语法糖:

let p = {
    let _tmp = Point::default();
    Point {
        x: _tmp.x, // assigning private field
        y: _tmp.y, // assigning private field
        z: 1,
    }
};

并没有达到预期:

// NOT what happens
let p = {
    let _tmp = Point::default();
    p.z = 1; // no private assignment
    _tmp
};

我有什么选择?

最惯用的选项是为 Point 提供

builder
。这也有点笨重1,所以如果您正在寻找一个简单的解决方案,您也可以使用
Point::default()
并手动设置
z
属性。结构更新语法与具有私有字段的结构不兼容,并且对您的类型没有用处。


1 尽管有诸如 derive_builder、typed-builder 和 builder-pattern 这样的板条箱可以减轻一些苦差事。


3
投票

A

new()
带参数或构建器。

..struct

只是进行功能更新的一种便捷方式,它不会绕过 ACL。由于您的结构具有私有字段,因此用户

不能

将其作为“裸”结构进行操作,他们必须将其视为很大程度上不透明的类型。

© www.soinside.com 2019 - 2024. All rights reserved.