Why does Rust allow public access to a private module? - module

I am a newbie in Rust and just started to read the programming book while doing rustling exercises. In the modules2.rs exercise, I am confused why the following code compiles:
mod delicious_snacks {
pub use self::fruits::PEAR as fruit;
pub use self::veggies::CUCUMBER as veggie;
mod fruits {
pub const PEAR: &'static str = "Pear";
pub const APPLE: &'static str = "Apple";
}
mod veggies {
pub const CUCUMBER: &'static str = "Cucumber";
pub const CARROT: &'static str = "Carrot";
}
}
fn main() {
println!(
"favorite snacks: {} and {}",
delicious_snacks::fruit,
delicious_snacks::veggie
);
}
Specifically, I am wondering why it is OK for main to access private fruits and veggies modules just because their uses are marked pub? On the other hand, if we don't use pub use, then, without making fruits and veggies pub, one cannot access e.g., delicious_snacks::fruits::PEAR in main because fruits is not public. Similarly, if we don't use pub for const PEAR, even with pub use self::fruits::PEAR as fruit, we still cannot compile delicious_snacks::fruit. So what exactly is the rule here? Why is it OK to not mark pub for those modules?

The constants PEAR/APPLE/CUCUMBER/CARROT are marked as pub, which means they can be accessed from everywhere, even if they're in a private module.
This is a common technique, to implement something in a private module, and re-export only the things we want, e.g.
// actual implementation is here
mod foo_internal;
pub use foo_internal::{Foo, Bar};
This still maintains privacy/visibility, since Foo and Bar can't be re-exported if they're private.
You can also create a new module hierarchy for users of your library:
mod foo_internal;
pub mod foo {
pub use foo_internal::Foo;
}
pub mod bar {
pub use foo_internal::Bar;
}
This clearly separates the public interface from implementation details, so the implementation can be freely refactored without changing the public modules.

Related

error[E0277]: the trait bound `my_struct::MyStruct: my_trait::MyTrait` is not satisfied

I am writing projects in Rust to help me learn it, but am having trouble implementing a trait and then using a function required by that trait when a type implementing it is passed to a function.
To try and narrow down the problem, I've created an MVCE. Here is the error message and code:
error message
error[E0277]: the trait bound `my_struct::MyStruct: my_trait::MyTrait` is not satisfied
--> src\main.rs:12:5
|
12 | invoke_print_i32(&MyStruct { });
| ^^^^^^^^^^^^^^^^ the trait `my_trait::MyTrait` is not implemented for `my_struct::MyStruct`
|
note: required by `invoke_print_i32`
--> src\main.rs:7:1
|
7 | fn invoke_print_i32<T: MyTrait>(instance: &T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
my_trait.rs
pub trait MyTrait {
fn print_i32(&self, n: i32);
}
my_struct.rs
#[path = "my_trait.rs"]
mod my_trait;
use my_trait::MyTrait;
pub struct MyStruct { }
impl MyTrait for MyStruct {
fn print_i32(&self, n: i32) {
println!("n: {}", n);
}
}
main.rs
mod my_trait;
use my_trait::MyTrait;
mod my_struct;
use my_struct::MyStruct;
fn invoke_print_i32<T: MyTrait>(instance: &T) {
instance.print_i32(42);
}
fn main() {
invoke_print_i32(&MyStruct { });
}
My attempts at researching the problem mostly found people trying to implement fairly standard Rust traits, for example:
How can I implement Rust's Copy trait?
The trait bound is not satisfied in Rust
The trait bound is not satisfied
I also read somewhere that I needed to reimplement the trait for variables such as &MyStruct, but my attempts to do so didn't resolve the issue.
extra info
rustc -V outputs rustc 1.36.0 (a53f9df32 2019-07-03)
cargo -V outputs cargo 1.36.0 (c4fcfb725 2019-05-15)
Platform/OS is Windows 10 Pro (x86_64)
question
What am I doing wrong; how can I correctly implement the trait?
You have declared the module my_trait twice, so there are actually two different traits called MyTrait: crate::my_trait and crate::my_struct::my_trait.
You don't need to declare the module in the my_struct module. Instead, use the module that is declared in the crate root, with:
use crate::my_trait::MyTrait;
Or
use super::my_trait::MyTrait;

Including a file from another that is not main.rs nor lib.rs

(I'm a Rust beginner) I have three files : main.rs, board.rs and case.rs.
I want to include case.rs into board.rs, and board.rs into main.rs, so the board uses the case, and we can access the board in main.
I've successfully added the board into main, but the way I did doesn't seem to work for the second part.
I've tried to encapsulate every file's content into "mod {}" but it doesn't change the problem.
Also I tried every combinations of "mod" and "use".
Every file is in the folder src/, and I'd like them not to move from there if possible.
main.rs
mod board;
fn main() {
let mut b: Board = Board::new();
}
board.rs
mod case;
pub struct Board {
board: [ Case; 9 ]
}
// There is also the impl part of course, let's keep it short
case.rs
pub enum Case { Empty, Full(Player) }
Using VSCode with the Rust plugin, the "case" word on the first line of the board.rs file is underlined red, and it says :
"src/case.rs
file not found for module case
help: name the file either board\case.rs or board\case\mod.rs inside the directory "src""
Why doesn't it search in the current directory?
Your files could look like as follows:
case.rs:
#[derive(Clone, Copy, Debug)]
struct Player;
#[derive(Clone, Copy, Debug)]
pub enum Case {
Empty,
Full(Player)
}
board.rs:
use crate::case::Case;
#[derive(Debug)]
pub struct Board {
board: [ Case; 9 ]
}
impl Board {
pub fn new() -> Self {
Self { board: [Case::Empty; 9] }
}
}
main.rs:
mod case;
mod board;
use crate::board::Board;
fn main() {
println!("{:?}", Board::new());
}
Basically you create a crate (a binary one, because of your main.rs) and that crate can have modules. A module can be a file, or it can be a folder as well (if it happens to have a mod.rs). (And for the sake of completeness, it could also be an inline module without direct relation to the file system.)
Your mod statements (the ones which are indicating files and folders, not the ones which you use to create inline modules) should either be placed at the top level of your crate (e.g. in your main.rs or lib.rs) or at the module levels (in your mod.rs files) depending on the desired structure.
For further info on this, please read the The Rust Programming Language book's relevant chapter: Packages and Crates.

I can't have every trait and impl in the same file; how to place in seperate file?

I have a struct, a trait, and impl in the top level file.
struct Model {}
trait TsProperties {
fn create_ar_x_matrix(&self);
}
impl TsProperties for Model {
fn create_ar_x_matrix(&self){}
}
I want to move the trait and impl to a separate file called test.rs. In the main file I have:
mod test
In test I have:
use crate::Model;
When I instantiate the struct, Intellisense does not pick up create_ar_x_matrix. If the code is in main.rs it does.
How do I resolve this?
If I add pub I get this error:
25 | pub impl TsProperties for Model {
| ^^^ `pub` not permitted here because it's implied
if I use pub on the struct in main file and put the trait in a separate file:
error[E0599]: no method named `create_ar_x_matrix` found for type `Model` in the current scope
--> src/main.rs:353:12
|
64 | pub struct Model {
| --------------------- method `create_ar_x_matrix` not found for this
You need to import the trait.
In test.rs:
use crate::Model;
pub trait TsProperties {
fn create_ar_x_matrix(&self);
}
impl TsProperties for Model {
fn create_ar_x_matrix(&self){}
}
In main.rs:
mod test;
use self::test::TsProperties;
struct Model {}
fn main() {
let model = Model {};
model.create_ar_x_matrix();
}
Note that Model doesn't need to be public, but the trait does. That's because anything in a parent module is automatically visible in child modules.

Rust Can't import Singleton From global space into another module in another file

Using the lazy_static library to create a singleton. I am unable to access that singleton in a module in another file. If the module is defined below the main function I can access it fine.
Given a main file such as the following, test_stuff can access gamedata fine:
extern crate gamedata;
#[macro_use]
extern crate lazy_static;
lazy_static! {
pub static ref GAMEDATA: &'static str = "I am a test STrings";
}
fn main() {
println!("Game Data:{}",*GAMEDATA);
let obj = gamedata::readinginstatic::readinginstatic {
structure:"working".to_string()
};
obj.print_static();
}
mod test_stuff {
use ::GAMEDATA;
fn printthing() {
println!("herenow:{}", *GAMEDATA);
}
}
With a lib.rs file such as:
pub mod readinginstatic;
And a module in another file readinginstatic.rs as described below:
use ::GAMEDATA;
pub struct readinginstatic {
pub structure:String,
}
impl readinginstatic {
pub fn print_static(&self) {
println!("In Print static width:{}", *::GAMEDATA);
}
}
I get the error:
not found in the crate root
When trying to import GAMEDATA.
Is it possible to access a lazy_static singleton in another module if it is defined in another file?
To insure I have provided a Minimal, Complete, and Verifiable example here is my whole example code on GitHub: https://github.com/camccar/moduleError
::GAMEDATA refers to some value called GAMEDATA in the crate root of the gamedata crate. However where you defined GAMEDATA was not in that crate, it was in your main.rs file which has gamedata as a dependency.
So what you're trying to do here is reach out of a crate use something from the crate that is depending on you, which I'm not sure but I don't think is allowed.
You could consider inverting this and instead initialising GAMEDATA inside your gamedata crate instead and if you need to use it in main you can just use it normally:
extern crate gamedata;
use gamedata::GAMEDATA;
fn main(){
println!("Game Data:{}", *GAMEDATA);
...
}
Alternatively if GAMEDATA is not something your game data crate should know how to define, you could construct it inside main and pass it to some function in the gamedata crate as a parameter.

How do I "export" things from a submodule?

I'd like to write a mod.rs file like:
pub use foo::*;
mod foo;
pub mod bar;
But I get the error unresolved import foo. What's the correct way to do this?
Here's an MCVE of your problem:
pub mod sub {
use foo::function;
pub mod foo {
pub fn function() {}
}
}
fn main() {}
As Adrian mentions, the solution is to use the keyword self in the use statement:
pub mod sub {
use self::foo::function;
pub mod foo {
pub fn function() {}
}
}
fn main() {}
So, what's going on? The Rust Programming Language describes the problem:
What about the self? Well, by default, use declarations are absolute paths, starting from your crate root. self makes that path relative to your current place in the hierarchy instead.
That is, use foo means to use foo from the root of the crate. use self::foo means to use foo relative to the current module.