Where is the recommended place to put use declarations? I couldn't find any decisive answer in the book, in FAQs, mailing lists or online forums. I'm beginning a new project in Rust and I'd prefer to get the right approach right away.
Is one of the two below approaches recommended? Is it only for "aliasing" stuff or does it do more, like initialize a module if it hasn't been used before?
use std::io;
use std::io::Write;
fn some_func() -> () {
[...] // We assume we need std::io here
}
fn some_other_func() -> () {
[...] // We assume we need std::io and std::io::Write here
}
OR
fn some_func() -> () {
use std::io;
[...] // We assume we need std::io here
}
fn some_other_func() -> () {
use std::io;
use std::io::Write;
[...] // We assume we need std::io and std::io::Write here
}
TL;DR: Like almost every other piece of software, it depends on what you are doing. The common style that I have observed (and prefer myself) is to put them at the top of the file and only moving them to narrower scope as needed.
Generally, I recommend starting by placing use statements directly after any extern crate and mod statements, separated by a blank line:
extern crate foo;
extern crate bar;
mod interesting;
use std::collections::HashMap;
use foo::Foo;
use bar::{Quux, moo};
use interesting::something;
// structs, functions, etc.
I base this default on the fact that — most times — an import is used in multiple top-level items. Thus, it makes sense to only import it once.
There are times where imported traits have conflicting methods, and in those cases I scope the import to where it's needed. There are also cases where I'm heavily dealing with a single enum and wish to glob-import it to avoid re-stating the enum's name:
fn foo(e: MyEnum) {
use MyEnum::*;
match e {
One => 1,
Two => 2,
}
}
In certain cases, conflicting use statements indicate that you are attempting too much in a single file and it should be split into separate files and then the use statements are no longer ambiguous.
Related
Recently, I started to learn rust. I'm currently at section 7.4 (bringing paths into scope). Tried hard, but I can't understand the purpose of self::some_sort_of_identifier in rust. Would you please explain what is the difference between use self::module_name::function_name and use module_name::function_name? I tried both and they both worked as expected in the example below:
mod my_mod {
pub fn func() {
print!("I'm here!");
}
}
use my_mod::func;
fn main() {
func();
}
Running this program, as expected, I can see this statement printed into the terminal:
I'm here
And this program here gives me exactly the same results and the rust compiler doesn't complain about anything:
mod my_mod {
pub fn func() {
print!("I'm here!");
}
}
use self::my_mod::func;
fn main() {
func();
}
So, is self:: useless in rust? Why should I even use self::my_mod::my_function(); when I can directly call it like so: my_mod::my_function();.
Are there any cases in which they might defer?
For your use-case, it's mainly a relict from the 2015 rust edition.
In this edition the following code would not compile:
use my_mod::func;
mod my_mod {
use my_mod2::func2;
pub fn func() {
func2();
}
mod my_mod2 {
pub fn func2() {
print!("I'm here!");
}
}
}
fn main() {
func();
}
The compiler complains:
error[E0432]: unresolved import my_mod2
--> src\main.rs:4:9
|
| use my_mod2::func2;
| ^^^^^^^ help: a similar path exists: self::my_mod2
Why did it change? You can see the note about the path and module system changes here.
Rust 2018 simplifies and unifies path handling compared to Rust 2015. In Rust
2015, paths work differently in use declarations than they do
elsewhere. In particular, paths in use declarations would always start
from the crate root, while paths in other code implicitly started from
the current scope. Those differences didn't have any effect in the
top-level module, which meant that everything would seem
straightforward until working on a project large enough to have
submodules.
In Rust 2018, paths in use declarations and in other code work the
same way, both in the top-level module and in any submodule. You can
use a relative path from the current scope, a path starting from an
external crate name, or a path starting with crate, super, or self.
The blog post Anchored and Uniform Paths from the language team also underlines this
The uniformity is a really big advantage, and the specific feature we’re changing -
no longer having to use self:: - is something I know is a big
stumbling block for new users and a big annoyance for advanced users
(I’m always having to edit and recompile because I tried to import
from a submodule without using self).
The keyword itself however is still useful in use statments to refer to the current module in the path itself. Like
use std::io::{self, Read};
being the same as
use std::io;
use std::io::Read;
I really don't like monolithic implementations of the functions for a class (in C++ speak). In that language I can split things up as I like; in Rust there are strict rules about what goes in what files.
I have about 2000 lines (no comments/ docs) of impl for a struct. Logically they can be broken up into different sets; functions for managing aspect A, functions for managing aspect B, ... They all noodle on the struct's data big time, so chopping the struct up further wont help.
I saw in one answer that you can have
// in thing.rs
struct Thing{
.......
}
impl Thing{
fn1
fn2
}
// in more_thing.rs
use crate::thing::*;
impl Thing{
fn3,
fn4
}
// in lib.rs
mod thing;
mod more_thing;
This works, almost (I was surprised it worked at all). Its a kind of half way house. The problem is that for the methods in more_thing.rs I have to declare the fields of Thing all pub. Which is doable but not great. Are there any other options?
I know I can limit the pub scope but still it blows encapsulation.
All non-pub items in a module are still visible in its submodules. Just make more_thing a submodule of thing instead of a sibling. You can do this by putting it in a directory named thing, and putting the mod declaration inside thing.rs:
// thing.rs (or thing/mod.rs; see below)
pub struct Thing {
field: i32,
}
// Note the lack of `pub`: `more` is only an implementation detail
mod more;
// thing/more.rs
use super::Thing;
impl Thing {
// Although it is defined in a non-`pub` module, this method will be visible anywhere
// `Thing` is because it is marked `pub` and is a member of `Thing`. You can use
// `pub(crate)` or `pub(super)` instead to get different levels of visibility, or
// leave it private and it will only be available in the current module (thing::more)
pub fn field(&self) -> i32 {
// because more is a submodule of thing, non-`pub` members are visible here.
self.field
}
}
If you wish to keep all the Thing-related files in the thing directory, you can rename thing.rs to the special filename thing/mod.rs and it will work in exactly the same way.
All methods are private by default in Rust, which means they are only accessible in the scope of their containing module (which is never larger than a file), in this case thing.rs. thing.rs is just as remote to more_thing.rs as any libraries and external code; it may as well be a separate crate. In essence, you are trying to declare a private method on an external item, which of course fails.
However, this can be a bit confusing because when it comes to orphan rules, you can always implement traits for any item in the same crate, not just the same module. This is because trait implementations are always public (as long as you can access both the trait and the item implementing it; the actual orphan rules are a bit more complicated but this is the basic idea).
In essence: trait implementations are public, but method implementations are private by default. In order to implement public things you need at least public access, and in order to implement private things you need private access.
Instead, one solution is to simply declare a function that takes your item as an argument. For example, in more_thing.rs:
use super::thing::Thing;
fn foo(thing: &Thing) {
// ...
}
Why not put impl blocks in the same file?
in thing.rs
struct Thing {
.......
}
impl Thing {
fn1
fn2
}
impl Thing {
fn3
fn4
}
The methods are splited though there is still a large file.
I have a crate that has lots of code, so I've split it into multiple files/modules. However, some modules have internal unsafe stuff (e.g. raw pointers) that I need to make public to the different modules, but I don't want to expose to users of my crate. How can I do that?
The only way I can think of is to actually have my crate just be one big module, but then there's no way to split it into different files, other than this solution which seems a bit hacky.
Normally when I come up against a real world problem that the simple examples in the Rust docs don't adequately explain I just copy a popular real world crate, e.g. git2-rs, but that just seems to effectively make everything public, including the raw pointers.
In order for an item to be exported from a library crate, there must be at least one path leading to it in which every component is public. This means that all you need to make an item public within your crate but not exported from the crate (I'll call this "internal" from now on, to mimic C# terminology) is to put it in a private module under the crate root.
However, that solution is quite restrictive. What if you'd like to have a module with exported functions and internal functions? In order to export some functions, we need to make the module public, and that mean all public items in that module will be exported as well.
Since Rust 1.18, there's a solution adapted to this kind of scenario: pub(restricted). This feature lets you specify "how public" an item should be. The syntax is pretty flexible (you can make an item visible to a particular module tree instead of the whole crate), but if you want to keep it simple, pub(crate) will make an item accessible anywhere within the crate, but not to other crates (equivalent to internal in C#).
For example, suppose we'd like to have a module util in which foo is exported (as mycrate::util::foo), bar is internal and baz is private to the module. The code might look like this:
pub mod util {
pub fn foo() {
unimplemented!()
}
pub(crate) fn bar() {
unimplemented!()
}
fn baz() {
unimplemented!()
}
}
If you're stuck on pre-1.18 Rust, there's a workaround, but it's a bit clunky. It involves defining all your items in private modules, and reexporting only those that you want to make public (with pub use) in public modules that only contain reexports. Here's what the example above would look like:
pub mod util {
pub use util_impl::foo;
}
mod util_impl {
pub fn foo() {
unimplemented!()
}
pub fn bar() {
unimplemented!()
}
fn baz() {
unimplemented!()
}
}
Not only is this not easy to read and understand, it doesn't cover all situations where pub can be used. For example, how would you make some fields of an exported struct accessible in other modules in the same crate without also exporting them? The only option would be to expose a wrapper with a single private field whose type is the struct that has public fields; that works fine if you want to hide all fields from other crates, but not if you want to expose some fields and make some other fields internal in the same struct.
I'm interested in using wasm-bindgen via rust-webpack-template to compile Rust code to WebAssembly. However, I'd like to avoid directly wrapping my code with the #[wasm_bindgen] attribute macro directly so that I can separate out the function logic from the generated WebAssembly interface to better organize my project. Instead, I would prefer to have binding generation be in a separate file, for example:
mod my_code;
use my_code::my_function;
#[wasm_bindgen]
my_function; // I want to do something like this!
I understand that #[wasm_bindgen] is a macro attribute that operates on the AST of the function definition that usually follows, but is there an approach for applying that macro to code defined elsewhere?
As far as I know, there's no way to do this. Macros operate on the AST of the code they are attached to, and there's no code to be attached to here.
If you really need this, you'll have to copy-and-paste the signature of your function:
mod my_code {
pub fn my_function(_: i32) -> String {
unimplemented!()
}
}
#[wasm_bindgen]
fn my_function(a: i32) -> String {
my_code::my_function(a)
}
It's possible you could write a macro to make the wrapping slightly less tedious, but you'll still need to replicate the function name, argument types, and return type.
I'm interested in using wasm-bindgen via rust-webpack-template to compile Rust code to WebAssembly. However, I'd like to avoid directly wrapping my code with the #[wasm_bindgen] attribute macro directly so that I can separate out the function logic from the generated WebAssembly interface to better organize my project. Instead, I would prefer to have binding generation be in a separate file, for example:
mod my_code;
use my_code::my_function;
#[wasm_bindgen]
my_function; // I want to do something like this!
I understand that #[wasm_bindgen] is a macro attribute that operates on the AST of the function definition that usually follows, but is there an approach for applying that macro to code defined elsewhere?
As far as I know, there's no way to do this. Macros operate on the AST of the code they are attached to, and there's no code to be attached to here.
If you really need this, you'll have to copy-and-paste the signature of your function:
mod my_code {
pub fn my_function(_: i32) -> String {
unimplemented!()
}
}
#[wasm_bindgen]
fn my_function(a: i32) -> String {
my_code::my_function(a)
}
It's possible you could write a macro to make the wrapping slightly less tedious, but you'll still need to replicate the function name, argument types, and return type.