强制使用构造函数

ber*_*kes 2 rust

我想对某些结构提供一些业务规则保证。例如,anEmailAddress是有效的电子邮件,或者 aDateRange的 from 位于 from 之前,等等。因此,当传递这样的值时,可以保证遵守该结构的所有业务规则。

struct InvalidEmailAddress;
struct EmailAddress {
  value: String
}

impl EmailAddress {
  fn new(value: String) -> Result<Self, InvalidEmailAddress> {
    if value.contains("@") { // I know, this isn't any sort of validation. It's an example.
        Ok(Self { value })
    } else {
        Err(InvalidEmailAddress)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

忽略 now 的new()行为是意外的(使用方法可能会更好build()),这会带来一个问题:当有人EmailAddress通过构造函数构建 an 时,它保证是“有效的”。但是当有人将其构造为普通结构时,它可能不是。

let guaranteed_valid = EmailAddress::new(String::from("hi@example.com")).unwrap();
let will_crash = EmailAddress::new(String::from("localhost")).unwrap()
let unknown_valid = EmailAddress { value: String::from("hi-at-example.com") }
Run Code Online (Sandbox Code Playgroud)

我想禁止这些结构的任何用户直接构造它们,就像最后一行一样。

这可能吗?还有其他方法可以以无效的方式构造电子邮件地址吗?

我同意将结构放置在模块中,并使用公共/私有可见性(如果可能的话)。但据我所知,任何现在想要强制执行该EmailAddress类型的代码(例如 a)send_report(to: EmailAddress)都可以访问该结构并可以直接构建它。或者我错过了一些重要的事情?

use*_*342 7

您需要将结构放入模块中。这样,该模块之外的任何代码都只能访问公共功能。由于value不是公开的,因此不允许直接构建:

mod email {
    #[derive(Debug)]
    pub struct InvalidEmailAddress;
    pub struct EmailAddress {
        value: String,
    }

    impl EmailAddress {
        pub fn new(value: String) -> Result<Self, InvalidEmailAddress> {
            if value.contains("@") {
                // I know, this isn't any sort of validation. It's an example.
                Ok(Self { value })
            } else {
                Err(InvalidEmailAddress)
            }
        }
    }
}

use email::EmailAddress;

fn main() {
    let e = EmailAddress::new("foo@bar".to_string()).unwrap(); // no error
    //let e = EmailAddress { value: "invalid".to_string() };   // "field `value` of struct `EmailAddress` is private"
}
Run Code Online (Sandbox Code Playgroud)

操场

有关可见性的更多详细信息,请参阅本书

  • 可能值得一提的是 [Rust 书中的相关章节](https://doc.rust-lang.org/reference/visibility-and-privacy.html) 以获取更多信息。 (2认同)