I was trying to understand how (sub)module imports work when using wildcard paths. The simplest demonstration I could come up with is as follows, where two modules, or perhaps two crates, share the same module structure.
pub mod primary {
pub mod a {
pub mod b {
pub struct A(pub i32);
}
}
}
pub mod import {
pub use crate::primary::*;
// Compiles and executes fine with this commented out, but fails with
// "error[E0433]: failed to resolve: could not find `b` in `a`"
// otherwise. The error refers to the usage in the assert_eq macro
// pub mod a {}
}
fn main() {
assert_eq!(import::a::b::A(42).0, 42);
}
My general thought, was, since the first case, where the pub mod a {} is commented out works, the wildcard should expand all submodules the wildcard picks up into submodules in the path in which it is expanding. Is this not the case? If so, what's the appropriate way to think about?
The Use declarations doesn't have a lot of detail on this.
use with a * imports all the names, except for those that would conflict with names that already exist in the current module.
Compare:
pub mod primary {
pub fn f() {
println!("p::f");
}
}
pub mod import {
pub use crate::primary::*;
}
fn main() {
import::f();
}
which prints p::f to
pub mod primary {
pub fn f() {
println!("p::f");
}
}
pub mod import {
pub use crate::primary::*;
pub fn f() {
println!("import::f");
}
}
fn main() {
import::f();
}
which prints import::f.
This might seem obvious for functions and constants (it would otherwise make * very limited, making it impossible for upstream libraries to add any item without risking to break downstream users), but it might seem more confusing for modules.
You have to remember though that you can't define a module multiple times (ie. "reopen" a module). The following is illegal:
pub mod primary {
pub mod a {}
pub mod a {}
}
and fails with
error[E0428]: the name `a` is defined multiple times
--> src/lib.rs:3:5
|
2 | pub mod a {}
| --------- previous definition of the module `a` here
3 | pub mod a {}
| ^^^^^^^^^ `a` redefined here
|
= note: `a` must be defined only once in the type namespace of this module
You can solve this particular case by adding one more level:
pub mod primary {
pub mod a {
pub mod b {
pub struct A(pub i32);
}
}
}
pub mod import {
pub mod a {
pub use crate::primary::a::*;
}
}
fn main() {
assert_eq!(import::a::b::A(42).0, 42);
}
A wildcard import creates aliases to all items on the top level of the module.
In your example, since primary contains only one item, a, the wildcard import creates an alias import::a, which refers to the module primary::a.
Whenever conflicts arise, explicitly named items are given higher precedence than items that were imported via a wildcard. Effectively, you can shadow a wildcard import by declaring a new item or by importing it by name from another module.
Each mod declaration declares a different module. There is no implicit merging of items in modules that happen to have the same name or alias.
Related
I have a code that looks approximately like this:
// src/bitboard.rs
#[derive(Copy, Clone, Debug)]
pub struct Bitboard {
value: u64
}
impl Bitboard {
pub const fn new(value: u64) -> Self {
Self { value }
}
pub const fn get_bit(&self, k: u64) -> u64 {
((1u64 << k) & self.value) >> k
}
}
// src/main.rs
pub mod bitboard;
use crate::bitboard::Bitboard;
fn main() {
let bitboard = Bitboard::new(0);
dbg!(bitboard);
}
If I compile it exactly like this, it works without any errors or warnings.
However, if I change my pub mod bitboard to mod bitboard, then clippy starts giving me this warning:
warning: this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
pub const fn get_bit(&self, k: u64) -> u64 {
^^^^^ help: consider passing by value instead: `self`
= note: `-W clippy::trivially-copy-pass-by-ref` implied by `-W clippy::pedantic`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
I understand what clippy is telling me to do. But I do not understand why it does not suggest this when my module is declared as public. Any ideas?
P.S.: I am using rustc 1.60.0, clippy 0.1.60.
Edit: I should also add that this is not the only extra lint that happens when I remove the pub from my modules. For instance, I also had 1 new clippy::upper_case_acronyms, and 1 new clippy::enum_variant_names.
Edit 2: As requested, I'm including more examples to show the same behaviour happening to clippy::upper-case_acronyms and clippy::enum_variant_names:
// src/fen.rs
pub struct FEN; // upper case acronyms happens here
pub enum FENValidationError { // enum variant names happens here
InvalidFieldsCount,
InvalidPiecePlacement,
InvalidRankSize,
}
// src/main.rs
mod fen; // same thing here. If this becomes `pub mod fen`, the two lint warnings above disappear.
Because changing a public API like that is a breaking change.
Changing the argument to pass by value like clippy recommends is easy if its an internal method, since you have control over all of the code that uses it. But if the argument is on a function or method exposed as part of the public API, changing it would require that all the other projects that use it change too, which is usually unacceptable for something as minor as passing a small Copy value by reference.
Is it possible to export a function and a macro with the same name from a module?
Example lib.rs
mod log;
fn foo() {
log::info!("");
log::info("");
}
In log.rs:
Using pub(crate) use info; conflicts with pub fn info() { .. }
Using #[macro_export] and #[macro_use] doesn't allow namespaces
Macros and functions belong to different namespaces so two with the same name should happily coexist. This compiles (playground):
macro_rules! info {
($v:expr) => {}
}
fn info(v: &str) { }
However, trouble seems to arise when when trying to make them public from within a module. Exporting the macro as shown in How do I use a macro across module files? seems to conflict somehow with the function declaration (playground):
mod log {
macro_rules! info {
($v:expr) => {}
}
pub(crate) use info;
pub fn info(v: &str) { }
}
error[E0255]: the name `info` is defined multiple times
--> src/lib.rs:8:5
|
6 | pub(crate) use info;
| ---- previous import of the value `info` here
7 |
8 | pub fn info(v: &str) { }
| ^^^^^^^^^^^^^^^^^^^^ `info` redefined here
|
= note: `info` must be defined only once in the value namespace of this module
help: you can use `as` to change the binding name of the import
|
6 | pub(crate) use info as other_info;
| ~~~~~~~~~~~~~~~~~~
I do not know if this is a bug or intended behavior. Either way it is confusing.
A workaround that I found was to declare the function in a separate module and then re-export it by wildcard in the original module (playground):
mod log {
mod imp {
pub fn info(v: &str) { }
}
pub use imp::*;
macro_rules! info {
($v:expr) => { }
}
pub(crate) use info;
}
You can do it the other way (i.e. putting the macro in a separate module) but the compiler strangely yields a warning that it didn't re-export anything even when it did (playground).
Here's the code:
use crate::rooms::room::RoomInterface;
pub mod dogroom {
pub struct R;
impl RoomInterface for R {
}
}
Here's /rooms/mod.rs:
pub mod room {
// Irrelevant stuff
pub trait RoomInterface {
// stuff
}
// stuff
}
Here's what it tells me:
I find it quite arcane that I import the very same thing it wants me to import, and yet it doesn't work.
I've tried pretty much all the permutations of the use keyword, and I can't make it work. What's going on?
uses are scoped to the module that imports them, not the file they are in.
Move the import into the dogroom module:
pub mod dogroom {
use crate::rooms::room::RoomInterface;
pub struct R;
impl RoomInterface for R {
}
}
Alternatively, you might want the dogroom module to reuse everything from the parent module:
use crate::rooms::room::RoomInterface;
pub mod dogroom {
use super::*;
pub struct R;
impl RoomInterface for R {
}
}
I'm having a bit of a headache trying to use traits defined in separate files to the implementation and was hoping somebody could point out where I am going wrong.
My file structure is this
main.rs
file1.rs
thing.rs
Contents of main.rs
mod file1;
mod thing;
fn main() {
let item : Box<dyn file1::Trait1> = Box::new(thing::Thing {});
}
file1.rs
pub trait Trait1 {
}
thing.rs
mod file1 {
include!("file1.rs");
}
pub struct Thing {
}
impl file1::Trait1 for Thing {
}
The error on compilation is:
error[E0277]: the trait bound `thing::Thing: file1::Trait1` is not satisfied
--> src/main.rs:9:41
|
9 | let item : Box<dyn file1::Trait1> = Box::new(thing::Thing {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `file1::Trait1` is not implemented for `thing::Thing`
|
= note: required for the cast to the object type `dyn file1::Trait1`
As far as I can tell file1::Trait1 is implemented. If not, what have I actually implemented?
mod file1 {
include!("file1.rs");
}
By writing this in thing.rs, you have created a module, thing::file1, which is distinct from the top-level module file1. Thus, you have two distinct versions of your trait, thing::file1::Trait1 and file1::Trait1.
This is almost never the right thing. As a general principle, every .rs file (except for main.rs, lib.rs, and other crate root files) should have exactly one mod declaration.
Delete the above code from thing.rs, and use use instead of mod, or a fully qualified path:
use crate::file1;
...
impl file1::Trait1 for Thing {
...
or
use crate::file1::Trait1;
...
impl Trait1 for Thing {
...
or
impl crate::file1::Trait1 for Thing {
...
In general, mod defines a module, and use brings items into scope. You write mod only once per module, and use wherever you want to refer to that module.
Rust has support for both pub and pub(super). pub makes it so the parent module can access an item... and pub(super) seems to also do exactly the same thing. I've tried playing with the example below, and swapping pub and pub(super) seems to have no effect:
#![allow(dead_code)]
mod outer {
pub(super) fn outer_foo() { inner::inner_foo(); }
mod inner {
pub(super) fn inner_foo() { println!("hello world!"); }
}
}
fn top_level_foo() { outer::outer_foo(); }
Why would you ever use one over the other?
Playground link.
In your example, if you change your inner module to be public, then the difference would become clear.
For example, this works because outer::inner::inner_foo is visible from the main module:
#![allow(dead_code)]
mod outer {
pub(super) fn outer_foo() { inner::inner_foo(); }
pub mod inner {
pub fn inner_foo() { println!("hello world!"); }
}
}
fn top_level_foo() { outer::outer_foo(); }
fn main() {
outer::inner::inner_foo();
}
If you kept inner_foo as pub(super) it would've been only visible from the outer module (because super refers to the super-module, outer in the case of something inside inner), hence the above code wouldn't compile and you would see this error:
|
13 | outer::inner::inner_foo();
| ^^^^^^^^^ private function
|
note: the function `inner_foo` is defined here
Notice that pub can also take crate as an argument, making the function public within the crate itself, but not to other crates.