Private by default
When you define a module, constant, type and so on, they are going to be private by default. As an effect, if you want code at some place outside of the module to use the code you are currently working on, you have to explicitly allow it. This alone can prevent heaps of messy code that doesn't scale well and will eventually fall apart.
For structs, the same rule applies with fields. Code outside of the module can't access private fields directly, only through public functions on the object. This is standard object oriented programming procedure. When all fields are public (or you have access to them anyway), you can create a new object of a struct through simply assigning all of its fields. Sometimes, you want to use structs to simply group data together. In this case, making all fields public is absolutely fine.
// You might have seen this in the first chapter already! struct MyStruct { pub data: usize } fn example() { let my_object = MyStruct { data: 42 }; println!("{}", my_object.data); } fn main() { example(); }
The Rust compiler also enforces a consistent privacy model, so if, for example, you would try to return an object of a private struct in a public function, you would receive a compiler error saying that the public function leaks a private type.
By now, you might have noticed that I explicitly wrote "outside of the module" a few times. This is because code in the same module, as well as in submodules, actually has private access. This is because Rust applies the same encapsulation rules as with code blocks: An inner scope, such as an if-block, has access to the variables of the scope it's defined in, but not the other way around. Declaring items public is the obvious exception to that rule, as it enables the export of items out of their scope.
This behaviour has a few interesting effects:
- Factoring out code into submodules becomes fairly easy, just encapsulate a part of your module, define an interface to access it from the outside, and you're done. The new module still has full access to the non-encapsulated parts. This enables fairly organic growth.
- Extending a module with something that needs private access becomes trivial. Most importantly, this enables unit testing in a separate submodule instead of relying on special functionality like
friend
classes in C++.