I think that use is used to import identifiers into the current scope and extern crate is used to declare an external module. But this understanding (maybe wrong) doesn't make any sense to me. Can someone explain why Rust has these two concepts and what are the suitable cases to use them?
extern crate foo indicates that you want to link against an external library and brings the top-level crate name into scope (equivalent to use foo). As of Rust 2018, in most cases you won't need to use extern crate anymore because Cargo informs the compiler about what crates are present. (There are one or two exceptions)
use bar is a shorthand for referencing fully-qualified symbols.
Theoretically, the language doesn't need use — you could always just fully-qualify the names, but typing std::collections::HashMap.new(...) would get very tedious! Instead, you can just type use std::collections::HashMap once and then HashMap will refer to that.
Since Rust 2018 you're only required to add external dependencies to your Cargo.toml, so you no longer need to use extern crate foo.
use works the same as before.
Read more in the official documentation.
Related
How do you get rust to recognize a module within a crate? I believed it was enough to declare mod [module name] in lib.rs. Is it not?
Error:
error[E0432]: unresolved import `crate::a`
--> src/bin/b.rs:2:12
|
2 | use crate::a::f;
| ^ could not find `a` in the crate root
src/a.rs:
pub fn f() {}
src/bin/b.rs:
use crate::a::f;
fn main() {}
src/lib.rs:
mod a;
Cargo.toml:
[package]
name = "m"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "b"
path = "src/bin/b.rs"
[dependencies]
You are confusing crates and packages. As per the corresponding chapter in the book:
A crate is the smallest amount of code that the Rust compiler considers at a time. [...] A crate can come in one of two forms: a binary crate or a library crate.
This means that your lib.rs and bin/b.rs files define two separate crates and thus crate refers to different things. Both belong to the same package which is defined by your Cargo.toml file. To use functions from your library crate in your binary crate, use the crate name instead of crate. In your case, the crate name is the same as the package name, which is m. Note that you will have to mark your library items as pub to use them in another crate.
An example of this can be found in the bat program, which uses both crate and bat in the imports of the bat binary crate:
https://github.com/sharkdp/bat/blob/2dbc88d3afdacf6449f299c70f29e5456904779b/src/bin/bat/main.rs
When a binary is compiled it is seen as the root of the project structure. So lib.rs is not compiled for binary targets and you can not use any of its modules unless you also add them in your binary. The most common approach is to put your binaries in the src folder with lib.rs so you don't need to worry about the folder structure when using your modules. I suppose you could use include!("lib.rs"); at the top of your binary to make it inherit everything from your library, but I have not tried it and it would likely be considered bad form.
However, you can sidestep the issue by making your binary depend on your library. The easiest way to do this is by making your binary its own crate which depends on your library.
There are also some ways to get around this, is by making a crate a dependency of itself, but these solutions always make me feel a little uneasy about the stability of the solution. This answer can give you a general idea of what that looks like.
Here are some examples various solutions. In case you are wondering, these are just the first crates I found that fit the design pattern. I do not know what some of them do/contain.
https://github.com/stanislav-tkach/os_info (Workspace members)
https://github.com/sagiegurari/cargo-make (Binaires in source)
https://github.com/hominee/dyer (Subcrates (dyer-macros))
https://github.com/clap-rs/clap (Example binaries)
I have a rust project with main.rs, some other modules in the main.rs level and several submodules underneath. I use the anyhow crate in almost all of them.
Is there a clean way to declare use anyhow; only once (probably in main.rs?) without the need to redclare its usage in every single mod/file?
Note that anyhow itself should be accessible without use (as of Edition 2018), because this is a crate name. If you mean to import something within that crate for your entire project (use anyhow::Context;), then no, there is no standard¹ way to have that.
Each module has its own scope for such symbols, which are imported via use. The one exception is in the standard preludes, defined by the compiler itself. These are what enable you to use Copy, Result, and others without having to import them explicitly. However, this is naturally out of your control.
There is also a common pattern for some libraries to provide their own prelude: a module that re-exports symbols that are likely to be useful. anyhow does not provide one at the time of writing.
See also:
What is the prelude?
¹Almost anything becomes possible with macros or another preprocessor, but it is hardly a good tradeoff for this case.
Rust doesn't support global imports.
However, for global macro imports, there is a way, as explained here. That won't solve your problem completely, but it will at least allow you to avoid importing the macros.
In your main.rs you can add this:
#[macro_use]
extern crate anyhow;
And then you can use macros like bail! and ensure! all around your project, without the need to explicitly import them.
I'd like to use a type returned by a function in crate A that is actually defined in crate B, but crate A doesn't reexport it.
Although I can explicitly add crate B in my Cargo.toml, I'm not sure how to keep its version sync with the one used in crate A.
To be more specific, the type is url::ParseError, crate A is reqwest and crate B is url.
There are no "official" guidelines around this issue. There was a discussion regarding best practices a while back with no definite conclusion. Many crates wrap external types so they aren't exposed directly, or they re-export items. This specific issue with reqwest was discussed here and it was decided to not re-export url::ParseError:
My personal feeling is that this is somewhat niche, and so for those who don't need it, it just clutters the API. For anyone who does need to inspect for this specific error, they can add the url crate as a dependency.
Many libraries that contain procedural macros consist of two crates: a proc-macro crate implementing the actual macro and a normal "main" crate that reexports or wraps the proc macro. This is done because proc-macro crates cannot publicly export anything other than proc macros. Assuming the main crate is called foo, the macro crate is usually called foo-derive or foo-macros.
This brings up a couple of questions about how to version the proc-macro crate. Of course, the main crate follows semantic versioning. But should the macro crate follow it as well? I don't want people to use the macro crate directly, but only through the main crate. I clearly stated that in the proc-macro crate's description. I want to treat the macro crate as an implementation detail.
In that case, can I shouldn't need to follow semantic versioning, right? The main crate would then just require one exact version via foo-macro = "=0.0.4".
Is this fine? Or can something break with this approach? Are there some established best practices in the community?
With the core library stabilized in Rust 1.6, the following becomes possible, and I do not need to replace libcore with libstd any more:
//extern crate core; //won't work without this line
extern crate num;
use core::ops::Add;
use num::bigint::{BigInt};
fn main() {
let mut big = "8705702225074732811211966512111".parse::<BigInt>().unwrap();
let one = "1".parse::<BigInt>().unwrap();
big = big.add(&one);
println!("{:?}", big);
}
But there is one thing puzzles me - why do I need to declare "extern crate core;"? As far as I know, libstd is meant to be built on top of libcore. libcore is meant to be OS independent, while the implementation of libstd can be OS specific. I never had the need to specify "extern crate std". What also puzzles me is that I do not need to add libcore as a dependency in Cargo.toml in the above case, although it is an extern crate.
Is libcore the only such case? Is this a temporary thing while the implementation of the language is getting stabilized?
In fact everything works in a pretty logical way.
First of all, libstd crate is indeed special. Rust compiler knows about it and it injects extern crate std; implicitly unless #![no_std] attribute is present on the crate root. Additionally it also imports standard prelude in every module of your crate (again, unless #![no_std] is present).
Now you can probably see why you have to specify extern crate core; while at the same time you don't need to specify extern crate std;. You also don't need to specify core in Cargo.toml because libcore, as well as several other libraries (libcollections, liballoc, liblibc, etc.; you can find an up-to-date list in Rust source directory) are present in the Rust compiler distribution. There is in fact a desire to allow these libraries to be available through Cargo as well (expressed in form of RFCs), but as of now these libraries are provided with the compiler distribution only.
And finally, remember that Rust crates are independent. Rust ABI is designed in such a way so you can have different versions of the same crate built into the final executable. While it is invalid for one crate to directly depend on multiple versions of the same crate, it is possible that its dependencies transitively depend on different versions of another crate. This is one of the reasons why you always have to explicitly specify dependencies of your crate: if you don't specify that your crate depends on libcore, even though libstd does depend on libcore, libcore won't be pulled by your crate automatically if it uses libstd.