You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2019-01-17-how-to-order-rust-code.md
+51Lines changed: 51 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -68,6 +68,57 @@ right next to the functions they are needed for.
68
68
> [I] love to read types upfront
69
69
> (if you know the set of fields, you know all potential methods that can exists)
70
70
71
+
### Where to put `use` statements?
72
+
73
+
To use an item (type, trait, function, etc.) that is not in scope
74
+
you can either refer to it by its full path
75
+
(e.g., `std::collections::HashMap`)
76
+
or import it using
77
+
`use std::collections::HashMap;`
78
+
after which you can refer it as just `HashMap`.
79
+
The issue is:
80
+
Where to put these `use` statements?
81
+
82
+
One typical approach is to put them all at the top of the file.
83
+
This "wall of imports"
84
+
is what you also see in many other programming languages.
85
+
This is a good idea if the only location you can put import statements
86
+
is at the root level
87
+
and especially if the file contains one "main item"
88
+
(e.g., if `foo.java` contains import statements followed by `class Foo { … }`).
89
+
In Rust, however,
90
+
you don't often have just one item at the root level.
91
+
You have a `foo.rs`
92
+
that contains a `struct Foo { … }`,
93
+
various `impl Bar for Foo { … }` blocks,
94
+
possibly some free functions,
95
+
and in many cases even unit tests.
96
+
So, we should rethink where to put these `use` lines!
97
+
98
+
One approach I've taken previously is
99
+
to keep `use`s as close to the area they are needed as possible.
100
+
If I have a function that reads five files,
101
+
I add a `use std::fs::File;` at the beginning _of that function._
102
+
Sadly,
103
+
this breaks down when you want to import a type
104
+
to use it in a function's/method's signature or as a field type in a struct:
105
+
In that case,
106
+
the use `use` needs to be on the level _above_ the usage point
107
+
(i.e., on the level of the function/trait/struct definition).
108
+
Additionally,
109
+
if you have `use std::sync::Arc` above one struct,
110
+
it becomes available in the general scope.
111
+
So, your next struct that uses `Arc`
112
+
doesn't need to have a second instance of that `use` line.
113
+
114
+
This all lead me to the point where
115
+
I often just go back to collecting `use`s at the top of the file.
116
+
I will however not write single `use` lines for all the items I want to use,
117
+
but instead
118
+
119
+
- only import the module when I use various items but each of them only a few times (e.g. `use std::sync;` and refer to `sync::Arc` and `sync::Mutex`.)
120
+
- make use of Rust's nested imports (e.g. `use std::{error::Error, fs, io::{self, Read}};)`.
121
+
71
122
### Split public and private interfaces
72
123
73
124
When the entry file of a package or module[^1] gets to long,
0 commit comments