It seems like I haven't fully understood Rust's module system yet. I have the following file structure:
module_issue
|_Cargo.toml
|_src
|_main.rs
|_lib.rs
|_bindings
|_mod.rs
This code compiles and runs without issues:
// file: bindings/mod.rs
pub fn say_hello() {
println!("Hello from the bindings module!");
}
// file: lib.rs
mod bindings;
pub fn try_bindings() {
bindings::say_hello();
}
// file: main.rs
use module_issue;
fn main() {
module_issue::try_bindings();
}
However, if I make a sub-module in lib.rs and try to use bindings::say_hello() from there, I get a compiler error. Here's what lib.rs now looks like:
// file: lib.rs
mod bindings;
pub fn try_bindings() {
bindings::say_hello();
}
mod debugging {
pub fn try_bindings_debug() {
bindings::say_hello(); // <- can't find 'bindings' - shouldn't it be in scope?
}
}
and this is the error I get:
error[E0433]: failed to resolve: use of undeclared type or module `bindings`
--> src\lib.rs:10:9
|
10 | bindings::say_hello();
| ^^^^^^^^ use of undeclared type or module `bindings`
error: aborting due to previous error
In lib.rs, I also tried replacing mod bindings; with use crate::bindings;, but that resulted in a different error:
error[E0432]: unresolved import `crate::bindings`
--> src\lib.rs:2:5
|
2 | use crate::bindings;
| ^^^^^^^^^^^^^^^ no `bindings` in the root
error[E0433]: failed to resolve: use of undeclared type or module `bindings`
--> src\lib.rs:10:9
|
10 | bindings::say_hello();
| ^^^^^^^^ use of undeclared type or module `bindings`
error: aborting due to 2 previous errors
My understanding of the module system was as follows: If I bring a module A into the scope of module B, then the public members of A will be accessible in B and all the sub-modules of B. In this case, I bring the bindings module into the scope of the library root. The debugging module is a sub-module of that root, so it should have access to bindings as well. Can you tell me where I went wrong? My priority isn't really to solve the problem, but to understand why this doesn't work.
I'm working on Windows 10, with the following toolchain:
cargo 1.39.0 (1c6ec66d5 2019-09-30)
rustc 1.39.0 (4560ea788 2019-11-04)
If I bring a module A into the scope of module B, then the public members of A will be accessible in B and all the sub-modules of B.
This assertion is incorrect. The scope of each module contains only things defined or used in the module itself, not in its parents.
You can, however, pull items from the parent explicitly:
mod debugging {
use super::bindings; // referring to library root
pub fn try_bindings_debug() {
bindings::say_hello();
}
}
Playground
Related
I'm newbie in Rust, and trying to compile Rust code into WASM:
use libloading::{Library, Symbol};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn main() {
// Load the DLL
let lib = unsafe { Library::new("file.dll").unwrap() };
let connect: Symbol<unsafe extern "C" fn(*const std::os::raw::c_char, *const std::os::raw::c_char) -> i32;> =
unsafe { lib.get(b"Function\0").unwrap() };
But when i run wasm-pack i'm getting the error:
error[E0432]: unresolved imports 'libloading::Library', 'libloading::Symbol'
--> src\lib.rs:1:18
|
1 | use libloading::{Library, Symbol};
| ^^^^^^^ ^^^^^^ no 'Symbol' in the root
| |
| no 'Library' in the root
For more information about this error, try 'rustc --explain E0432'`.
error: could not compile 'rust' due to previous error
Error: Compiling your crate to WebAssembly failed
Caused by: failed to execute 'cargo build': exited with exit code: 101
full command: "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown"`
If my undestanding is right - libloading can'not complie to WASM.
Does any one know way to comple such Rust code into WASM? Or may be there is any other approach to access functions from dll file in JS (React).
I'm trying:
change 'release' in toml file;
compile in binary file;
I am learning rust, now tried to import a struct, this is the source file path app_root/src/model/response/playlist_response.rs, I am import another struct like this:
#[path = "../../models.rs"]
mod models;
use models::QueryPlaylist;
the model.rs path is app_root/src/models.rs, the models.rs file look like this:
use super::schema::posts;
use super::schema::playing_record;
use super::schema::favorites;
use super::schema::songs;
use super::schema::playlist;
use super::schema::album;
use rocket::serde::Serialize;
#[derive(Insertable,Serialize,Queryable)]
#[table_name="playlist"]
pub struct QueryPlaylist {
pub id: i64,
pub creator: i64,
pub name: String,
pub cover_url: Option<String>,
pub description: Option<String>,
pub subscribed: Option<i32>,
pub subscribed_count: Option<i64>,
pub comment_count: Option<i64>,
pub share_count: Option<i32>,
pub play_count: Option<i32>
}
when I compile the project, shows error like this:
$ cargo build ‹ruby-2.7.2›
Compiling reddwarf_music v0.1.0 (/Users/dolphin/Documents/GitHub/reddwarf_music)
error[E0432]: unresolved import `super::schema`
--> src/biz/music/../../model/response/../../models.rs:1:12
|
1 | use super::schema::posts;
| ^^^^^^ could not find `schema` in `super`
error[E0432]: unresolved import `super::schema`
--> src/biz/music/../../model/response/../../models.rs:2:12
|
2 | use super::schema::playing_record;
| ^^^^^^ could not find `schema` in `super`
error[E0432]: unresolved import `super::schema`
--> src/biz/music/../../model/response/../../models.rs:3:12
|
3 | use super::schema::favorites;
| ^^^^^^ could not find `schema` in `super`
error[E0432]: unresolved import `super::schema`
--> src/biz/music/../../model/response/../../models.rs:4:12
|
4 | use super::schema::songs;
| ^^^^^^ could not find `schema` in `super`
error[E0432]: unresolved import `super::schema`
--> src/biz/music/../../model/response/../../models.rs:5:12
|
5 | use super::schema::playlist;
| ^^^^^^ could not find `schema` in `super`
error[E0432]: unresolved import `super::schema`
--> src/biz/music/../../model/response/../../models.rs:6:12
|
6 | use super::schema::album;
| ^^^^^^ could not find `schema` in `super`
the schema.rs file path is app_root/src/schema.rs. I am import using the wrong way? what is the problem like this way? what should I do to make it work? This is the main.rs:
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate diesel;
// #[macro_use]
// extern crate redis;
#[path="biz/music/music.rs"] mod music;
#[path="config/db/config.rs"] mod config;
#[path="biz/music/songs.rs"] mod songs;
#[path="biz/music/test.rs"] mod test;
#[path="biz/user/user.rs"] mod user;
#[path="biz/music/playlist.rs"] mod playlist;
#[launch]
fn rocket() -> _ {
rocket::build()
.mount("/music/music", routes![music::play_record,music::save_play_record,music::like,music::dislike])
.mount("/music/songs",routes![songs::detail])
.mount("/music/user",routes![user::recent_found])
.mount("/music/playlist",routes![playlist::user_playlist])
.mount("/music/test", routes![test::detail])
}
You should not use #[path = ...] to try to import models.rs. It will declare a new module instead of using it as declared in main.rs. This in turn messes up how it imports stuff since super doesn't mean the same thing.
Instead you should simply import it using:
use crate::models;
See also:
Use module from parent directory in rust
Why do I get "expected struct file1::A found struct file2::A" error when using a struct in multiple files?
Clear explanation of Rust’s module system
Generally this is how you work with different files in your project:
Say you have this structure:
.
├── app
│ ├── some_logic.rs
├── database
│ ├── models.rs
├── config.rs
└── main.rs
In main.rs you declare:
mod config;
mod database{
pub mod models;
}
mod app {
pub mod some_logic;
}
Then you can use any public member of i.e. models.rs with: database::models::SomeStruct.
Same goes for some_logic.rs whose members you access with app::some_logic::SomeStruct. Of course config.rs's members are simply accessed with config::SomeStruct.
Say you want to access a constant MY_CONSTANT withing main.rs from models.rs:
fn function_within_models_rs() {
println!("Constant: {}", crate::MY_CONSTANT)
}
And accessing pub const LOGIC_CONSTANT: i32 = 222; declared in some_logic.rs from within models.rs:
fn function_within_models_rs() {
println!("Constant: {}", crate::app::some_logic::LOGIC_CONSTANT)
}
As you see, elements that are accessed from outside of the module there are declared in, need to be declared as pub (public). The compiler is great in giving you hints about what needs to be set to public so I would suggest keeping things private until you really want to use them somewhere else.
I have the following code:
pub mod a {
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
}
I get errors when I compile this:
error[E0433]: failed to resolve. Use of undeclared type or module `std`
--> src/main.rs:4:24
|
4 | println!("{}", std::fs::remove_file("Somefilehere"));
| ^^^ Use of undeclared type or module `std`
However, removing the inner module and compiling the code it contains by itself works fine:
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
What am I missing here? I get the same errors if the module is in a separate file:
main.rs
pub mod a;
a.rs
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
By default, the compiler inserts extern crate std; at the beginning of the crate root (the crate root is the file that you pass to rustc). This statement has the effect of adding the name std to the crate's root namespace and associating it with a module that contains the public contents of the std crate.
However, in child modules, std is not automatically added in the module's namespace. This is why the compiler cannot resolve std (or anything that starts with std::) in a module.
There are many ways to fix this. First, you can add use std; in a module to make the name std refer, within that module, to the root std. Note that in use statements, the path is treated as absolute (or "relative to the crate's root namespace"), whereas everywhere else, paths are treated as relative to the current namespace (be it a module, a function, etc.).
pub mod a {
use std;
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
}
You can also use a use statement to import more specific items. For example, you can write use std::fs::remove_file;. This lets you avoid having to type the whole path to remove_file and just use the name remove_file directly within that module:
pub mod a {
use std::fs::remove_file;
#[test]
pub fn test() {
println!("{:?}", remove_file("Somefilehere")));
}
}
Finally, you can avoid using use altogether by prefixing the path with :: to ask the compiler to resolve the path from the crate's root namespace (i.e. turning the path into an absolute path).
pub mod a {
#[test]
pub fn test() {
println!("{:?}", ::std::fs::remove_file("Somefilehere"));
}
}
The recommended practice is to import types (structs, enums, etc.) directly (e.g. use std::rc::Rc;, then use the path Rc), but to use functions through an import of their parent module (e.g. use std::io::fs;, then use the path fs::remove_file).
pub mod a {
use std::fs;
#[test]
pub fn test() {
println!("{:?}", fs::remove_file("Somefilehere"));
}
}
Side note: You can also write self:: at the beginning of a path to make it relative to the current module. This is more often used in use statements, since other paths are already relative (though they are relative to the current namespace, whereas self:: is always relative to the containing module).
Nowadays, std is directly accessible from everywhere, so the code you showed is compiling as you would expect.
Furthermore, extern crate is no longer needed in Rust edition 2018. Adding a dependency to Cargo.toml makes the crate name directly available as a top-level identifier.
I am used to organising files in separate directories depending on the problem domain (for example grouping image processing stuff together, IO stuff in another directory etc). I am not sure if this way or organisation is even recommended in Rust.
I have setup my project in multiple directories:
- helloworld
- Cargo.toml
- src
- main.rs
- test
- one.rs
I am trying to use a function from one.rs in main.rs
one.rs
fn test() {
println!("Calling test...");
}
main.rs
use test::one::*;
fn main() {
println!("Hello, world!");
test();
}
This results in a compile time error:
error[E0432]: unresolved import `test::one::*`
--> src/main.rs:1:5
|
1 | use test::one::*;
| ^^^^^^^^^^^^^ Maybe a missing `extern crate test;`?
error[E0425]: cannot find function `test` in this scope
--> src/main.rs:6:5
|
6 | test();
| ^^^^ not found in this scope
Looking at some online projects, it seems like something like this should be possible.
It is possible, however you need to inform your code about additional module that is inside your code using:
mod test;
And then create additional file
// src/test/mod.rs
pub mod one;
I have the following code:
pub mod a {
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
}
I get errors when I compile this:
error[E0433]: failed to resolve. Use of undeclared type or module `std`
--> src/main.rs:4:24
|
4 | println!("{}", std::fs::remove_file("Somefilehere"));
| ^^^ Use of undeclared type or module `std`
However, removing the inner module and compiling the code it contains by itself works fine:
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
What am I missing here? I get the same errors if the module is in a separate file:
main.rs
pub mod a;
a.rs
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
By default, the compiler inserts extern crate std; at the beginning of the crate root (the crate root is the file that you pass to rustc). This statement has the effect of adding the name std to the crate's root namespace and associating it with a module that contains the public contents of the std crate.
However, in child modules, std is not automatically added in the module's namespace. This is why the compiler cannot resolve std (or anything that starts with std::) in a module.
There are many ways to fix this. First, you can add use std; in a module to make the name std refer, within that module, to the root std. Note that in use statements, the path is treated as absolute (or "relative to the crate's root namespace"), whereas everywhere else, paths are treated as relative to the current namespace (be it a module, a function, etc.).
pub mod a {
use std;
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
}
You can also use a use statement to import more specific items. For example, you can write use std::fs::remove_file;. This lets you avoid having to type the whole path to remove_file and just use the name remove_file directly within that module:
pub mod a {
use std::fs::remove_file;
#[test]
pub fn test() {
println!("{:?}", remove_file("Somefilehere")));
}
}
Finally, you can avoid using use altogether by prefixing the path with :: to ask the compiler to resolve the path from the crate's root namespace (i.e. turning the path into an absolute path).
pub mod a {
#[test]
pub fn test() {
println!("{:?}", ::std::fs::remove_file("Somefilehere"));
}
}
The recommended practice is to import types (structs, enums, etc.) directly (e.g. use std::rc::Rc;, then use the path Rc), but to use functions through an import of their parent module (e.g. use std::io::fs;, then use the path fs::remove_file).
pub mod a {
use std::fs;
#[test]
pub fn test() {
println!("{:?}", fs::remove_file("Somefilehere"));
}
}
Side note: You can also write self:: at the beginning of a path to make it relative to the current module. This is more often used in use statements, since other paths are already relative (though they are relative to the current namespace, whereas self:: is always relative to the containing module).
Nowadays, std is directly accessible from everywhere, so the code you showed is compiling as you would expect.
Furthermore, extern crate is no longer needed in Rust edition 2018. Adding a dependency to Cargo.toml makes the crate name directly available as a top-level identifier.