rust 如何约束结构的构造?

p8h8hvxi  于 2023-02-19  发布在  其他
关注(0)|答案(2)|浏览(119)

是否可以禁止直接从成员初始化创建示例?
例如:

pub struct Person {
    name: String,
    age: u8,
}

impl Person {
    pub fn new(age: u8, name: String) -> Person {
        if age < 18 {
            panic!("Can not create instance");
        }
        Person { age, name }
    }
}

我还能用

Person {
    age: 6, 
    name: String::from("mike")
}

来创建示例。有什么办法可以避免这种情况吗?

ni65a41a

ni65a41a1#

问题答案

不能通过成员初始化创建该结构体,因为成员默认为私有,不能直接使用。只有立即模块及其子模块可以访问私有字段、函数等(请参阅有关可见性的书籍)。
您的示例可以工作,因为您的函数位于该特定范围内。

mod foo {
    pub struct Person {
        name: String,
        age: u8,
    }

    impl Person {
        pub fn new(age: u8, name: String) -> Person {
            if age < 18 {
                panic!("Can not create instance");
            }
            Person { age, name }
        }
    }
}

use foo::Person; // imagine foo is an external crate

fn main() {
    let p = Person {
        name: String::from("Peter"),
        age: 8,
    };
}

Playground

error[E0451]: field `name` of struct `Person` is private
error[E0451]: field `age` of struct `Person` is private

使从外部创建结构成为可能

另一方面,如果希望通过成员初始化创建示例,请在all成员前面使用pub关键字。

pub struct Person {
    pub name: String,
    pub age: u8,
}

允许访问字段,但不能从外部创建结构

请参阅KittenOverflows answer以获得更好的方法。

--
有时候,让crate的用户直接访问成员是很有用的,但是你想限制示例的创建,只允许你的"构造函数"创建,只需添加一个私有字段。

pub struct Person {
    pub name: String,
    pub age: u8,
    _private: ()
}

由于无法访问_private,因此无法直接创建Person的示例。
此外,_private字段阻止通过更新语法创建结构体,因此此操作失败:

/// same code from above

fn main() {
    let p = Person::new(8, String::from("Peter"));
    let p2 = Person { age: 10, ..p };
}
error[E0451]: field `_private` of struct `foo::Person` is private
  --> src/main.rs:27:34
   |
27 |     let p2 = Person { age: 10, ..p };
   |                                  ^ field `_private` is private
n3ipq98p

n3ipq98p2#

对于Rust〉= 1.40.0,请考虑将non_exhaustive属性应用于您的结构。

// Callers from outside my crate can't directly construct me
// or exhaustively match on my fields!
#[non_exhaustive]
pub struct Settings {
  pub smarf: i32,
  pub narf: i32,
}

更多信息请参见1.40.0发行说明。

相关问题