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.
Related
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
I am trying to configure an example project in Rust to work.
My structure is:
src/potter.rs
tests/tests.rs
And my Cargo.toml
[package]
name = "potter"
version = "0.1.0"
authors = ["my name"]
[dependencies]
My potter.rs contains:
pub mod potter {
pub struct Potter {
}
impl Potter {
pub fn new() -> Potter {
return Potter {};
}
}
}
And my tests.rs contains:
use potter::Potter;
#[test]
fn it_works() {
let pot = potter::Potter::new();
assert_eq!(2 + 2, 4);
}
But I receive this error:
error[E0432]: unresolved import `potter`
--> tests/tests.rs:1:5
|
1 | use potter::Potter;
| ^^^^^^ Maybe a missing `extern crate potter;`?
error[E0433]: failed to resolve. Use of undeclared type or module `potter`
--> tests/tests.rs:6:19
|
6 | let pot = potter::Potter::new();
| ^^^^^^ Use of undeclared type or module `potter`
warning: unused import: `potter::Potter`
--> tests/tests.rs:1:5
|
1 | use potter::Potter;
| ^^^^^^^^^^^^^^
|
= note: #[warn(unused_imports)] on by default
If I add extern crate potter;, it doesn't fix anything...
error[E0463]: can't find crate for `potter`
--> tests/tests.rs:1:1
|
1 | extern crate potter;
| ^^^^^^^^^^^^^^^^^^^^ can't find crate
Go back and reread The Rust Programming Language about packages, crates, modules and the filesystem.
Common pain points:
Every programming language has its own way of dealing with files — you cannot just assume that because you've used any other language that you will magically get Rust's take on it. That's why you should go back and re-read the book chapter on it.
Each file defines a module. Your lib.rs defines a module of the same name as your crate; a mod.rs defines a module of the same name as the directory it's in; every other file defines a module of the name of the file.
The root of your library crate must be lib.rs; binary crates may use main.rs.
No, you really shouldn't try to do non-idiomatic filesystem organization. There are tricks to do most anything you want; these are terrible ideas unless you are already an advanced Rust user.
Idiomatic Rust does not generally place "one type per file" like many other languages. Yes, really. You can have multiple things in one file.
Unit tests usually live in the same file as the code it's testing. Sometimes they will be split out into a file containing the submodule, but that's uncommon.
Integration tests, examples, benchmarks all have to import the crate like any other user of the crate and can only use the public API.
To fix your issue:
Move your src/potter.rs to src/lib.rs.
Remove pub mod potter from src/lib.rs. Not strictly required, but removes needless nesting of modules.
Add extern crate potter to your integration test tests/tests.rs (Only needed if you are using Rust 2015).
filesystem
├── Cargo.lock
├── Cargo.toml
├── src
│ └── lib.rs
├── target
└── tests
└── tests.rs
src/lib.rs
pub struct Potter {}
impl Potter {
pub fn new() -> Potter {
Potter {}
}
}
tests/tests.rs
use potter::Potter;
#[test]
fn it_works() {
let pot = Potter::new();
assert_eq!(2 + 2, 4);
}
I have a project layout that looks like the following:
src/
int_rle.rs
lib.rs
tests/
test_int_rle.rs
The project compiles with cargo build, but I am unable to run the test with cargo test. I get the error
error[E0432]: unresolved import `int_rle`. There is no `int_rle` in the crate root
--> tests/test_int_rle.rs:1:5
|
1 | use int_rle;
| ^^^^^^^
error[E0433]: failed to resolve. Use of undeclared type or module `int_rle`
--> tests/test_int_rle.rs:7:9
|
7 | int_rle::IntRle { values: vec![1, 2, 3] }
| ^^^^^^^^^^^^^^^ Use of undeclared type or module `int_rle`
error: aborting due to 2 previous errors
error: Could not compile `minimal_example_test_directories`.
My code:
// src/lib.rs
pub mod int_rle;
// src/int_rle.rs
#[derive(Debug, PartialEq)]
pub struct IntRle {
pub values: Vec<i32>,
}
// tests/test_int_rle.rs
use int_rle;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
int_rle::IntRle { values: vec![1, 2, 3] }
}
}
// Cargo.toml
[package]
name = "minimal_example_test_directories"
version = "0.1.0"
authors = ["Johann Gambolputty de von Ausfern ... von Hautkopft of Ulm"]
[dependencies]
Related: How do I compile a multi-file crate in Rust? (how to do it if the test and source files are in the same folder.)
The files src/int_rle.rs and src/lib.rs form your library, and together are called a crate.
Your tests and examples folders are not considered part of the crate. This is good, because when someone uses your library, they don't need your tests, they just need your library.
You can fix your issue by adding the line extern crate minimal_example_test_directories; to the top of tests/test_int_rle.rs.
You can read more about Rust's crate and module structure in the book, here.
This should be a working version of your test file:
// tests/test_int_rle.rs
extern crate minimal_example_test_directories;
pub use minimal_example_test_directories::int_rle;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
super::int_rle::IntRle { values: vec![1, 2, 3] };
}
}
I am trying to write a crate called bar, the structure looks like this
src/
├── bar.rs
└── lib.rs
My src/lib.rs looks like this
#![crate_type = "lib"]
#![crate_name = "bar"]
#![feature(ip_addr)]
#[allow(dead_code)]
pub mod bar;
My bar.rs has
pub struct baz {
// stuff
}
impl baz {
// stuff
}
Now when I try to use this crate in another crate like:
extern crate bar;
use bar::baz;
fn main() {
let cidr = baz::new("Hi");
println!("{}", cidr.say());
}
This fails with
error: unresolved import `bar::baz`. There is no `baz` in `bar`
Do I need to declare the module somewhere else?
The important part you are missing is that crates define their own module. That is, your crate bar implicitly defines a module called bar, but you also have created a module called bar inside that. Your struct resides within this nested module.
If you change your main to use bar::bar::baz; you can progress past this. You will have to decide if that's the structure you want though. Most idiomatic Rust projects would not have the extra mod and would flatten it out:
src/lib.rs
pub struct Baz {
// stuff
}
impl Baz {
// stuff
}
Unfortunately, your example code cannot compile, as you have invalid struct definitions, and you call methods that don't exist (new), so I can't tell you what else it will take to compile.
Also, structs should be PascalCase.
I have a main.rs file and a logging module inside logging.rs file. My file layout is:
.
├── Cargo.toml
├── src
│ ├── logging.rs
│ └── main.rs
The contents of my main.rs
mod logging;
fn main(){}
The contents of logging.rs
extern crate serialize;
use self::serialize::{json, Encoder, Encodable};
#[deriving(Encodable)]
pub struct Person {
pub age: i32
}
However this does not compile. The error is:
error: failed to resolve. Did you mean `self::serialize`?
/Users/valentin/../src/logging.rs:7 #[deriving(Encodable)]
Three questions:
Why does not it compile?
Why does moving the struct and use directive to main.rs makes it compile?
Why does changing serialize::Encodable to Show trait makes it compile even inside logging module?
However
If I add
extern crate serialize;
use self::serialize::{json, Encoder, Encodable};
to main.rs, it all starts compiling.
This is very confusing, the fourth questions is why isn't it sufficient to have only one extern crate + use serialize::.. inside logging module?
Let’s look at the code that’s generated, with rustc main.rs --pretty expanded:
#![feature(phase)]
#![no_std]
#![feature(globs)]
#[phase(plugin, link)]
extern crate std = "std";
extern crate rt = "native";
use std::prelude::*;
mod logging {
extern crate serialize;
use std::prelude::*;
use self::serialize::{json, Encoder, Encodable};
pub struct Person {
pub age: i32,
}
#[automatically_derived]
impl <__S: ::serialize::Encoder<__E>, __E>
::serialize::Encodable<__S, __E> for Person {
fn encode(&self, __arg_0: &mut __S) ->
::std::result::Result<(), __E> {
match *self {
Person { age: ref __self_0_0 } =>
__arg_0.emit_struct("Person", 1u, |_e| {
return _e.emit_struct_field("age", 0u,
|_e|
(*__self_0_0).encode(_e));
}),
}
}
}
}
fn main() { }
This demonstrates that the #[deriving(Encodable)]expands to stuff involving the paths ::serialize::*; that is, the item serialize from the crate root.
Now, extern crate serialize; from inside mod logging means that the path to serialize is ::logging::serialize, which is also accessible as self::serialize inside the module; there is no ::serialize.
The solution is moving the extern crate serialize; into the crate root. (This is where all extern crate definitions should be.) This is what fixed it for you, not the use self::serialize::{json, Encoder, Encodable};.