如何限制结构的构造?

McG*_*ady 6 rust

是否可以直接从成员初始化中禁止创建实例?

例如

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 }
    }
}
Run Code Online (Sandbox Code Playgroud)

我仍然可以Person {age: 6, name:String::from("mike")}用来创建实例.反正有没有避免这个?

小智 21

对于 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,
}
Run Code Online (Sandbox Code Playgroud)

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

  • 尽管我相信属性会更清晰,但这感觉就像使用某个功能是为了其副作用,而不是其主要用途,这可能会向 API 用户发送错误的消息。 (5认同)

hel*_*low 9

不,您无法从成员初始化创建该结构,因此您的问题已经是答案.

这是因为默认情况下,成员是私有的,不能直接使用.只有直接模块及其子模块才能访问私有字段,函数......(请参阅有关可见性的书籍).

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,
    };
}
Run Code Online (Sandbox Code Playgroud)
error[E0451]: field `name` of struct `Foo::Person` is private
error[E0451]: field `age` of struct `Foo::Person` is private
Run Code Online (Sandbox Code Playgroud)

另一方面,如果您希望通过成员初始化创建实例,请pub在所有成员前面使用关键字.

pub struct Person {
    pub name: String,
    pub age: u8,
}
Run Code Online (Sandbox Code Playgroud)

有时让您的包的用户直接访问成员是有用的,但您希望将实例的创建限制为"构造函数".只需添加一个私有字段.

pub struct Person {
    pub name: String,
    pub age: u8,
    _private: ()
}
Run Code Online (Sandbox Code Playgroud)

由于无法访问_private,因此无法Person直接创建实例.