Rust 为什么无法访问不同模块中的私有字段?

huangapple go评论72阅读模式
英文:

Why can't Rust access private fields when a struct is in a different module?

问题

constructors
    |---------src
    |          |----------lib.rs
    |          |----------constructor_file.rs    
    |
    |----------Cargo.toml
    |----------main.rs

lib.rs

pub mod constructor_file;

constructor_file.rs

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

impl Person {
    pub fn new(name: String, age: u32) -> Person {
        Person { name, age }
    }
    pub fn show(self) {
        println!("Name: {}, Age: {}", self.name, self.age);
    }
}

main.rs

use constructor_lib::constructor_file::Person;

fn main() {
    let person = Person { name: "Alice".to_string(), age: 33 };
    person.show();
    let person2 = Person::new("Bob".to_string(), 99);
    person2.show();
}

Cargo.toml

[package]
name = "constructor_lib"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "constructor_exe"
path = "main.rs"

The above project is giving me the following build error

C:\git\Rust examples\constructors>cargo build
   Compiling constructor_lib v0.1.0 (C:\git\Rust examples\constructors)
error[E0451]: field `name` of struct `Person` is private
 --> main.rs:4:27
  |
4 |     let person = Person { name: "Alice".to_string(), age: 33 };
  |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ private field

error[E0451]: field `age` of struct `Person` is private
 --> main.rs:4:54
  |
4 |     let person = Person { name: "Alice".to_string(), age: 33 };
  |                                                      ^^^^^^^ private field

For more information about this error, try `rustc --explain E0451`.
error: could not compile `constructor_lib` due to 2 previous errors

C:\git\Rust examples\constructors>

Why doesn't this error show up when I keep Person in the same file as main.rs?

main.rs

//use constructor_lib::constructor_file::Person;
pub struct Person {
    name: String,
    age: u32,
}

impl Person {
    pub fn new(name: String, age: u32) -> Person {
        Person { name, age }
    }
    pub fn show(self) {
        println!("Name: {}, Age: {}", self.name, self.age);
    }
}

fn main() {
    let person = Person { name: "Alice".to_string(), age: 33 };
    person.show();
    let person2 = Person::new("Bob".to_string(), 99);
    person2.show();
}
英文:

constructors
    |---------src
    |          |----------lib.rs
    |          |----------constructor_file.rs    
    |
    |----------Cargo.toml
    |----------main.rs

lib.rs

pub mod constructor_file;

constructor_file.rs

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

impl Person {
    pub fn new(name: String, age: u32) -> Person {
        Person { name, age }
    }
    pub fn show(self)
    {
        println!("Name: {}, Age: {}", self.name, self.age);
    }
}

main.rs

use constructor_lib::constructor_file::Person;

fn main() {
    let person = Person { name: "Alice".to_string(), age: 33 };
    person.show();
    let person2 = Person::new("Bob".to_string(), 99 );
    person2.show();
}

cargo.toml

[package]
name = "constructor_lib"
version = "0.1.0"
edition = "2021"

[[bin]]
name="constructor_exe"
path="main.rs"

The above project is giving me the following build error

C:\git\Rust examples\constructors>cargo build
   Compiling constructor_lib v0.1.0 (C:\git\Rust examples\constructors)
error[E0451]: field `name` of struct `Person` is private
 --> main.rs:4:27
  |
4 |     let person = Person { name: "Alice".to_string(), age: 33 };
  |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ private field

error[E0451]: field `age` of struct `Person` is private
 --> main.rs:4:54
  |
4 |     let person = Person { name: "Alice".to_string(), age: 33 };
  |                                                      ^^^^^^^ private field

For more information about this error, try `rustc --explain E0451`.
error: could not compile `constructor_lib` due to 2 previous errors

C:\git\Rust examples\constructors>

Why doesn't this error show up when I keep Person in the same file as main.rs?

main.rs

//use constructor_lib::constructor_file::Person;
pub struct Person {
    name: String,
    age: u32,
}

impl Person {
    pub fn new(name: String, age: u32) -> Person {
        Person { name, age }
    }
    pub fn show(self)
    {
        println!("Name: {}, Age: {}", self.name, self.age);
    }
}

fn main() {
    let person = Person { name: "Alice".to_string(), age: 33 };
    person.show();
    let person2 = Person::new("Bob".to_string(), 99 );
    person2.show();
}

答案1

得分: 3

因为这是 Rust 中的可见性工作方式

> 如果一个项是私有的,它可以被当前模块及其子模块访问。

如果结构体是在 main.rs 中定义的,那么 main.rs 是“模块或其子模块”的一部分,因此私有字段是可访问的。

如果结构体是在子模块中定义的,那么 main.rs 是“模块或其子模块”的一部分,私有字段是不可访问的。

正如书中也有记录的,与许多其他编程语言不同,因为 Rust 的隐私基线非常严格,你可以更灵活地定义可见性,而不仅仅是“公共”的。

特别地,你可以将一个符号定义为 pub(super) 以使其从父模块中访问,以及 pub(crate) 以使其从整个 crate 中访问。

在许多语言中(例如 Java),默认情况类似于 pub(crate),而“私有”的访问必须被选择。在 Rust 中,情况正好相反,因为“私有”是默认的(尽管比 Java 的 private 权限宽松一些,我认为)。

英文:

Because that's how visibility works in Rust?

> If an item is private, it may be accessed by the current module and its descendants.

If the structure is defined in main.rs, then main.rs is part of "the module or its descendant", thus private fields are accessible.

If the structure is defined in a sub-module, then main.rs is not part of "the module or its descendant", and private fields are not accessible.

As also documented in the book, and unlike many other languages, because Rust's privacy baseline is so restrictive you have a lot more flexibility in defining visibility than just "public".

Notably, you can define a symbol as pub(super) to make it accessible from the parent module, and pub(crate) to be accessible from the entire crate.

In many languages (e.g. java) the default is something like pub(crate), and "private" has to be opted in. In Rust, it's the other way around, "private" is the default (although it's a bit more relaxed than Java's own private, I think).

huangapple
  • 本文由 发表于 2023年3月7日 19:17:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75661299.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定