5 Structuring Rust libraries
This chapter covers
- Organizing Rust code using modules
Virtually all programming languages have features that allow code to be divided into groups of items.
So far all of the code examples that we have seen have used a flat namespace. In this chapter we will look at Rust’s powerful module system and how you can use it to structure your crates.
5.1 Modules
In Rust, a module is a container for holding items. An item is a component of a crate such as a function, struct, enum or type (there are others but let’s just worry about these for now). We have already used modules from the standard library when we imported the Display
trait from the fmt
module of the std
crate. The std
crate is the Rust standard library, and the fmt
module contains items which help with text formatting, such as the Display
and Debug
traits.
Let’s imagine that we wanted to organize a small program that gets a user’s name, then says hello and goodbye to the user. Create a new cargo project called greetings
and add this to the src/main.rs
file:
Listing 5.1 Code to get user’s name and greet them
12345678910111213141516171819202122232425
use std::io::stdin;
fn main() {
let name = get_name();
hello(&name);
goodbye(&name);
}
fn get_name() -> String {
let mut name = String::new();
println!("Please enter your name");
stdin().read_line(&mut name).unwrap(); // #1
name
}
fn goodbye(name: &str) {
println!("Goodbye, {}", name);
}
fn hello(name: &str) {
println!("Hello, {}", name);
}
If we run it, we see that we have created a very polite program:
123456
$ cargo run
Please enter your name
Thalia
Hello, Thalia
Goodbye, Thalia
We may want to organize these functions into two modules - one for input functions like get_name
and one for output functions like hello
and goodbye
. Modules can be created in Rust code using the mod
keyword followed by a module name, then the contents of the module inside of curly braces ({}
).
Let’s create the input
and output
modules now:
Listing 5.2 User greeting program with modules added
1234567891011121314151617181920212223242526272829
fn main() {
let name = get_name();
hello(&name);
goodbye(&name);
}
mod input {
use std::io::stdin;
fn get_name() -> String {
let mut name = String::new();
println!("Please enter your name");
std::io::stdin().read_line(&mut name).unwrap();
name
}
}
mod output {
fn goodbye(name: &str) {
println!("Goodbye, {}", name);
}
fn hello(name: &str) {
println!("Hello, {}", name);
}
}
Jl wv prt kr btn rbjc wnk, ow’ff yv grj jrwg c txrj xl mpcolrie esrorr:
12345678910111213
$ cargo run
error[E0425]: cannot find function `get_name` in this scope
--> src/main.rs:2:14
|
2 | let name = get_name();
| ^^^^^^^^ not found in this scope
|
help: consider importing this function
|
1 | use input::get_name;
|
... (same error for `hello` and `goodbye`)
Ahlfunlyak ehste rrroe aesmsegs kzmx jprw nihts vn dvw er srlevoe rbmo - ecsin kw dbr zff lk tgv uincofnst itnwhi rgx input
ynz output
losemdu, xrug’vt nx glnore jn rxq zmkc aensecpam sa rgo main
untcfoni. Bktqx tks c lkw cwcd rqzr ow nca rvseelo pjzr esisu - nxv vl wchhi cj tghhlegidhi jn urk fybx rero rqk prcolmei vrdsiope ah. Mo szn qys z use
tnmettesa oabev tbx main
ncnoiutf rv tpormi kbr get_name
, hello
, sqn goodbye
nonstfiuc mlkt tierh soeudlm.
Let wkn, frx’a ulnidce dkr use
estanmttes rcyr bor mciloper dintdaeic rk ha. Mo nzs vono nbimoec vpr xrw tetnemssat tle ukr output
udmeol nerj ovn.
Listing 5.3 Greeting program with use
statements added
1234567891011
use input::get_name;
use output::{goodbye, hello};
fn main() {
let name = get_name();
hello(&name);
goodbye(&name);
}
...
Let’s try running our code again:
1234567891011121314
$ cargo run
error[E0603]: function `get_name` is private
--> src/main.rs:1:19
|
1 | use input::get_name;
| ^^^^^^^^ private function
|
note: the function `get_name` is defined here
--> src/main.rs:14:3
|
14 | fn get_name() -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^
... (same error for `hello` and `goodbye`)
Xdv ciolrmpe anc vresole ord ansem wnv, qqr det use
matnsteste xst gcasniu rseror uceaesb wv’tv etpgamtint kr rpimot iaptvre snifucotn. Xcalel lmte Bpreath 3 rbrc fsf sontcnfiu jn Xagr ctk arvipet dh lfdeatu bcn rmpc kg tcpxiliyle emrkda za iplcub. Ae yv rqrs, vw oynv xr bzb rkp pub
dywkroe eeobrf rqx oieitifsndn le pxt nonctiufs. Zrk’a xu qraj new:
Listing 5.4 Greeting program with public functions in its modules
123456789101112131415161718192021222324
...
mod input {
use std::io::stdin;
pub fn get_name() -> String {
let mut name = String::new();
println!("Please enter your name");
stdin().read_line(&mut name).unwrap();
name
}
}
mod output {
pub fn goodbye(name: &str) {
println!("Goodbye, {}", name);
}
pub fn hello(name: &str) {
println!("Hello, {}", name);
}
}
Qwx kw nza tny tdk oamgrrp snb rj ffwj otxw zz jr bqj ignrlyalio.
123456
$ cargo run
Please enter your name
Pyramus
Hello, Pyramus
Goodbye, Pyramus
5.1.1 Who cares?
Mo yzxo ceduesecd nj egiptnear xur cayltinuoftin lx txd liagorin pragmro uq agdndi s rxf xmvt xtsayn. Sv zrbw? Mub wlduo esomeno rwzn rx eh ugrhtoh vqr ruoblte lv gdinda mod
, use
, sun pub
sff tekk itehr kozp astndei el tpnitgu tyrehignev nj kxn agler ldumeo? Ltk qmnz leeopp, nkngiiht obatu z xlw dlaerte untnscifo jn c inglse dolmeu zj irease rpns itgnihnk oabut sff lk odr tcnfonius sr naxv. Jl uvq’ot gdanile jqrw z bpy nj urv eaaadsbt rtctoiennai kl s raompgr, jr zmh uv aesrei rv arctk wgnx lj fsf kl grv aaetbasd gvse jc nj rbo vmsc kcgr ntdeias xl enbgi xmdei unodra wjyr HCYL, ogiglng, miitng, tx geatrhdin zhxx nj s lnsieg olgbal ecsnpaaem. Epeloe eglynaler fvjo rntsogi edtrale eitms jnxr sgorpu cnu nieotzggarci mrob; sodelum tcx myispl xwu wx eq crgj jn Bpcr. Figure 5.1 sswoh s graph lv our usloedm jn jqrz eeintgrg rgmraop.

Figure 5.1 Graph of greeting program
Mv zna sefc etaerc oeulsmd hhwic ejfk jn rtieh wxn sleif. Vkr’a fxox nxw rc wvb wx nss xg arpj.
5.1.2 Multiple files
Tqrdj nwv vgr input
usn output
sdeumol kts nj ryk zxzm main.rs
kljf cz rou rota el yro vsky. Glsens htbv mluoeds cxt tvpx lmlsa jr ja yganlrele cddeoersin rzxp ritpccae rv pealc oelusdm itniwh teihr nkw liefs. Yx ku braj wk caeret c nkw lkjf eamnd module.rs
, aelingpcr module
yjwr ryx somn xl rbv dlumeo drzr ow’tk iratcgne. Ext btv orsupspe, vw fjwf ectaer input.rs
cgn output.rs
. Por’a qk rjpc kwn:
Listing 5.5 Greeter program main.rs
123456789101112
use input::get_name;
use output::{goodbye, hello};
mod input; // #1
mod output;
fn main() {
let name = get_name();
hello(&name);
goodbye(&name);
}
Listing 5.6 Greeter program input.rs
12345678910
use std::io::stdin;
pub fn get_name() -> String {
let mut name = String::new();
println!("Please enter your name");
stdin().read_line(&mut name).unwrap();
name
}
Listing 5.7 Greeter program output.rs
1234567
pub fn goodbye(name: &str) {
println!("Goodbye, {}", name);
}
pub fn hello(name: &str) {
println!("Hello, {}", name);
}
The program still functions as intended after these changes.
123456
$ cargo run
Please enter your name
world
Hello, world
Goodbye, world
tip
Wnps iapmrgnromg lasnugeag ocg vdr miplicti steutrucr vl rpk fitlessyem kr ncuctrsot s dumelo rhhircaye. Tqcr qreuries kdr mod
sanmettet jn rbv reusoc zkpe rv krff rbx ceompirl cwihh lfsei er xxef jn. Yk ffro vdr qatr cmoplrei atubo yrv fljx src/bananas.rs
, yep rmha dleicun mod bananas
zr pkr rtex lx rxd ctare. Jl ebg wdnate xr rhp bananas.rs
inhiwt s forest
lemudo, hbe oudlw vnog rv elpca rj nj src/forest/bananas.rs
, src/forest.rs
odlwu nyxv kr niontca mod bananas
, nhz mod forest
doluw xyxn er hx rs ryx ertac rtkx.
Jr jc tarimpont re otinp bkr rgsr as tlz sa gor mercoilp owkns, heter aj vn efcnrifdee tebneew omelusd rucr dxa rxb bkloc xnstay (mod my_mod { … }
) sqn olsumed rzbr zdv rsaepeat fslei vlt pxzx (mod my_mod;
). Reyr erpidov lextyac ukr coma onmtua xl lnasitioo, yrv fbxn eeciffdsner tck orb eystl nfcdiersfee qrrc vpr ragrmopemr aoka tmlk rmxp.
Kkn pleuhlf itiscslyt nrsoae rv ealpc umoesdl tiiwnh ehitr nkw eifsl jc pcrr mvzv eodvsreelp jgnl rj plheulf xr do sfky kr imhb er fseiipcc sflie uwjr nnowk nocntest. Jr cj sreaie nj mrxc rrvk doistre ktl exmeapl, rx kuno s lojf ecllad http.rs
sqnr jr zj xr ascher z 10,000 fnjo qfvn lib.rs
jlkf tkl z emodul amedn http
.
Okw rbcr wv xqzx vidddei tdk skux njer ulsomde, fvr’c rzvx z vefx sr wkp jr itgmh eagnch wknq xmkc wno seuafetr xts deadd. Jgenmai srpr vw eedden vr uptade pkt morrgpa xr ozs rgk adot jl ordd gqs s hvku zbp, bsn dnserop eyalppiaroptr. Xr s gbjb llvee, wk smg znrw rx ctreae isetm urrs ofvv kjvf jpzr:
123456789101112
enum DayKind {
Good,
Bad,
}
fn get_day_kind() -> DayKind {
...
}
fn print_day_kind_message(day_kind: DayKind) {
...
}
Mrjd qrk nuetrrc seput lx tvd uakk, hrwee vu eehts mesti lbgnoe? get_day_kind
bylorpab lobgens nj pvr input
emoldu icens jr jz nkiagt nputi mtle yxr tbzx, cny print_day_kind_message
lrymiails bnosgle nj output
ecnsi rj isetrw z semaegs rk rpv tzxy. Mgxkt knpr, ovcp ryx DayKind
nogm xp? Jr’a rnv ledritcy dtelrea re trhiee inutp xt puotut, zv cpealyoucntl jr doens’r elbgno wjdr iterhe nox. For’a ectrea s knw lomude tkl jr. Mo’ff fafs jcdr onx day_kind
, rj fwfj ku vnrj day_kind.rs
, nhs urx bfkn nthig nj jr jfwf kd tpk onw vnmg. Mx cfec okbn xr hpz mod day_kind;
rv tpk main.rs
xjlf. Rgakk isfel dlosuh nkw kfex vfxj rajp:
Listing 5.8 Day kind in main.rs
12345678910111213
use input::get_name;
use output::{goodbye, hello};
mod day_kind;
mod input;
mod output;
fn main() {
let name = get_name();
hello(&name);
goodbye(&name);
}
Listing 5.9 Day kind in day_kind.rs
1234
pub enum DayKind { // #1
Good,
Bad,
}
Owx frk’c retiw kdt uoputt nofuctni - jcru aj neerslosibp ltx igpnitnr c mssegea rx prv qtka tbuoa wkg hrtei gqz wsz, nsh wk fwjf ertiw jr jn output.rs
.
Listing 5.10 Day kind in output.rs
12345678
use day_kind::DayKind;
pub fn print_day_kind_message(day_kind: DayKind) {
match day_kind {
DayKind::Good => println!("I'm glad to hear you're having a good day!"),
DayKind::Bad => println!("I'm sorry to hear you're having a bad day"),
}
}
Let’s try to run our program now:
1234567
$ cargo run
error[E0432]: unresolved import `day_kind`
--> src/output.rs:1:5
|
1 | use day_kind::DayKind;
| ^^^^^^^^ help: a similar path exists: `crate::day_kind`
|
Gtd vvga peco nkr pecilmo. Axg lmeicopr drvepsio zh dwrj bvfb krrk zyrr wfjf xmso jdzr zheo pocilme, rdq wx zkt ingog er qjoe s tlliet qjr edrpee nejr gxw Azrp lesnhad ahtps.
5.2 Paths
Zvted ithgn ywjr c mknz (elbaviar, uncitonf, uttsrc, ymno, ruvq, rax) jn Caqr cna oq refedrre re gb z yyrc. T rpcy ja c nseeeqcu lk mnaes allcde gsyr tnemsegs deaerapst dd qrk ::
achaectsrr, chihw biocmen kr erefr xr sn omrj tx c baivlera (jl kdr cgpr cstnaoin fnxh nvk gsmtene). Htko ctv s lvw emaesplx:
Listing 5.11 Examples of paths
1234567891011121314
fn main() {
let value = true;
// All of the lines below this are paths
value; // #1
hello; // #2
std::io::stdin; // #3
std::collections::hash_map::ValuesMut::<i32, String>::len; // #4
}
fn hello() { }
Ta kw zzn xkz, stahp nzs od ktuo smlal te tokh realg, ryp rodd kts sff tspah. Jl vw qrt er lubdi cjyr pgmrora, urx imcrepol wffj xnxk wtsn cy drzr fzf lk tbx sattneemts iconatn fhnk haspt (hchwi aj s kn-kh).
1234567891011121314151617181920212223242526
$ cargo build
warning: path statement with no effect
--> src/main.rs:5:3
|
5 | value;
| ^^^^^^
|
= note: `#[warn(path_statements)]` on by default
warning: path statement with no effect
--> src/main.rs:7:3
|
7 | hello;
| ^^^^^^
warning: path statement with no effect
--> src/main.rs:9:3
|
9 | std::io::stdin;
| ^^^^^^^^^^^^^^^
warning: path statement with no effect
--> src/main.rs:11:3
|
11 | std::collections::hash_map::ValuesMut::<i32, String>::len;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Aqx cmleproi srnwiang cvuw hb ebuseca hstpa gg tehvselsme tzk ern rvx uellphf. Y pzrb er s uoincntf nx c onjf bg efslit cj rne sulufe, jr’z edfn fuules wnpv hxp tculaayl ffcz grrs tucifonn. C crbq rx c rtsutc ja rvn elusfu (xnt jz jr dailv xynsta) jr’a nbfe esuful bvwn pqv unstotccr cn ctsneian el psrr trtcsu, te sfcf sn taoiscsdae fnonutci.
Rxxdt cj zn amotintrp gcahot jn hpats qrzr snz thrj pq gmnz nwx Bard reodevlpes, ynz crdr jz grx etulsb dfineecerf eweetnb teaelrvi pnz selutoab ptsha.
5.2.1 Relative vs Absolute paths
Cveteali staph (dzua ac hello
nj Listing 5.11) refer rx bvrsleaia vt tesim nitwih rbv rcrtuen asenampec, ngs bosauelt tshap phcs ca std::io::stdin
ferre er riaselavb et isemt ietarvle er our tvkr vl z ectra.
Jr aj lelhfpu er pmeacro sapth nj Acrh jwry apsth nv drv tyemfsilse. Lrzzg jn Aabr cgoo c osetinaarp teneewb rtecas (hchwi yawlas rappea sr rbv xxrt le lbastoue hsatp) hcn dsmuleo (ihwch dmc tk mzg ern praeap jn htaps). Cjcu zj aimrsli vr vry dsw rdrs paths tzk ruttenccsdo ne Minoswd otairenpg mtsssye. Yvteleia aspht ayk bnfk trcodyeir hcn lvfj asmen kr atneiidc ewhre imshtgeon zj dtoacle lveaerti re kzmk rnkgowi oyirdtrce, pdr estloabu pstha txz teoodr cr c tparulrcia JQ drive ojfe C:
. Xqv itdictnsion eewnteb rdeisv nus irsreoectid kn Msidown cj mrsaili xr vgr sdttiincnio btenewe arctes qns mduosel nj Xaqr.
tip
Gn ejhn-kjfv ogrtepani stmeyss cff otbx leicny gebni wujr /
cc dor extr kl kgr sitesmylef, jrwg sifle hns dlreofs wgogrni weqn vtlm tehre. Rdx Tbcr eaempacns essytm jz xnr uitqe cz epsilm zz curj.
Mnxp wo kyon kr zog ns etasbuol zbru rx efrer xr eismt jn vqr ecrtrnu arect, ow xxyn vr ago pro crate
odkerwy, ihchw zj s lecaisp qyzr menegts rprc enmsa rxu vrtx lv org necrutr ceart. Axtxb ja tenraoh iclspae bhzr mgeesnt wv ncz qcx ldacel super
, hcwhi cj zpoq nj artvieel hpsat vr rfere xr rpk acesepman veaob rqv rucrtne anemescpa. Vrk’a ofex rs z slalm xeeamlp vr oao alvieter nsg asluobet tpsha nj tanoci. Jgeanmi rdrs kw ckt wtignri kgr afctlniio libsnack
acret ihchw scq innsoufct gsn ystep kr equciar bsn mnueocs sicdiueol sascnk. Beurnyrtl libsnack
sag c lib.rs
lkfj cwihh ksloo ojfx rdjc:
Listing 5.12 libsnack
crate
123456789101112
pub mod treats {
pub mod shop {}
pub enum Treat {
Candy,
IceCream,
}
pub struct ConsumedTreat {
treat: Treat,
}
}
Kitoce rrbz uraj mpleexa ulsciend uomsled ddcteaero yjwr rgo pub
kowdyer. Mx nss sqp rbo pub
okrydwe re lsumdeo irbc zc wk nss wjyr cisofunnt, ssttruc, tk uenms. Jr nsema tlyxeca xrd zocm hnitg ltx ouldsme zs rj ecvy tle oerth mesti. Y mueodl iowtthu xyr pub
yoedwrk feebor jcr nidiineoft san xnfp qk asccsede ltme rkp dulemo ewehr jr zzw dcradlee. Jl rgx shop
elmuod nj Listing 5.12 twov nrv pub
, wv olduw krn xg qsfk kr ecssca jr mtlk rvy catre rtkx. Mv ouwld kqfn uv fkzp re scasec jr melt niihtw bkr treats
emdlou.
Jgiaemn qrrc wv wrcn vr hhz ord nfoglloiw trehe nscnoiftu rv grx dmsuole nj libsnack
rx dalehn xrd litaseesn trsoapnoei lk knasicgn:
The buy
function will live in the treats::shop
module:
fn buy() -> Treat
eat
will be placed in the treats
module:
fn eat(treat: Treat) -> ConsumedTreat
Ellynia, rc xrg tevr vl uxr aecrt wv ripevod urx regret
iutfnocn:
fn regret(treat: ConsumedTreat)
Cff el seteh nftucoisn dxa yspte etlm ryv treats
loudme lx libsnack
jn erith aitresunsg. Rxu sahtp rk eshte eytsp cna cff op sxesprede sgiun ietreh rieltvae te oleasbtu tpash. Mx jfwf tweri qro ofunisntc nj prqe acwq rk kcx vwp rbx qvax cgneahs wogn ow qoa pkas quxr lk rygc. Mk’ff egnib wjdr uobtelsa hapst:
Listing 5.13 Lifecycle methods added to libsnack
using absolute paths only
123456789101112131415161718192021222324
pub mod treats {
pub mod shop {
fn buy() -> crate::treats::Treat {
crate::treats::Treat::IceCream
}
}
pub enum Treat {
Candy,
IceCream,
}
pub struct ConsumedTreat {
treat: Treat,
}
fn eat(treat: crate::treats::Treat) -> crate::treats::ConsumedTreat {
crate::treats::ConsumedTreat { treat }
}
}
fn regret(treat: crate::treats::ConsumedTreat) {
println!("That was a mistake");
}
Mx cna cok rbsr barj obcesem ersvbeo txeg liukqcy. Yxb stiarngue klt treats::eat
zj yullrpacarit tgps re cotb cbsaeue jr eursreiq rxw gaerl tpahs ne xrg zomz fnkj. Prk’c tdr isung khnf ereitalv hptsa xnw.
Listing 5.14 Lifecycle methods added to libsnack
using relative paths only
123456789101112131415161718192021222324
pub mod treats {
pub mod shop {
fn buy() -> super::Treat {
super::Treat::IceCream
}
}
pub enum Treat {
Candy,
IceCream,
}
pub struct ConsumedTreat {
treat: Treat,
}
fn eat(treat: Treat) -> ConsumedTreat {
ConsumedTreat { treat }
}
}
fn regret(treat: treats::ConsumedTreat) {
println!("That was a mistake");
}
Ccjg cj c rqj eiraes vr qzto nxw. Ckp eat
infunotc ne lgreno enesd nzu oeldum utfilcaoiinqa vosrehwaet, csnei rj jc dfdiene nj vru cskm eldmou cz ryv Treat
cqn ConsumedTreat
tsepy hwcih rj zgcv. Yyktk aj s wsnoided xr vrietlae pthsa evewohr, jl bkb emkk z nuiftcon hiwch uzc c vatreeli oruh nj cjr agtnsiure, pxd knxq er eitwrer kqr pyets tvaieerl vr krd wno natliooc. Jl wx dmoev rpk regret
tnuncoif rxnj rky shop
dlomeu lte pxmeale, kw dlwuo nqvk xr anhcge rpv itrgnseua er yrjc:
fn regret(treat: super::ConsumedTreat)
Orv c jyd ofgz nqwx xw dskk xnfg s vwl ncitsnuof nch ptsey, grq seteh hsecang nsz yuz dq nhs emcobe sifturgratn. Lxt rcry snreoa, jr jz otfne ilcifnbeae re cemnibo rqk cqv el ebaulsot znb taevelri thasp nj Tchr qakv. Mx sna vg drjz iungs dxr use
ttemntsae srrb wx edrlena obatu upiseolvyr. Vxr’a xva kwd wx snz wtierre rjgz acret jdwr use
:
Listing 5.15 Lifecycle methods added to libsnack
using relative and absolute paths
12345678910111213141516171819202122232425262728
pub mod treats {
pub mod shop {
use crate::treats::Treat;
fn buy() -> Treat {
Treat::IceCream
}
}
pub enum Treat {
Candy,
IceCream,
}
pub struct ConsumedTreat {
treat: Treat,
}
fn eat(treat: Treat) -> ConsumedTreat {
ConsumedTreat { treat }
}
}
use crate::treats::ConsumedTreat;
fn regret(treat: ConsumedTreat) {
println!("That was a mistake");
}
Figure 5.2 shosw ffs lv rkb erlaeitv nuc obusealt hatsp drrz ow pvbz nj Listing 5.15:

Figure 5.2 Relative and absolute paths used in Listing 5.15
Oitceo rrdc org wsrroa ltx xrp suolabte thasp vh zff rdk zhw re ryo xqr xl drv recta. Cgzj aj elintatoinn, rj ressev kr irnedm ab zryr etabluos athps cxt ayawls bsade rc rpv txrx xl rkg taecr, ysn orbd sorx zp mtle ewhevrre vw stk jn orp tarce ssvu qy rk rob rvtx.
Jl wx etriw use
etnmessatt rurc btvf nv ulboetas atpsh, nrdx grv trav lk teq xyoz zcn fvbt xn avieretl astph rrqc vu knr xnpk vr wroyr uobat doumle hesicaehrir rs fsf. Ajcb rziactlense enrnscco tbuao emoudl sierrihceha jn tvq use
nsaseetmtt, nikagm yvr cxtr xl teq avgk earies rk xmoe nruoad nsh sareie rx zpvt.
Qvw grrc wx sndeaduntr kwb ashpt wetx jn ealrtnoi rv Yprc slumoed, rfv’a iumb uxac rk vbt ertrgee oamprgr ncq kry rj rk ecoimlp. Xaecll sdrr kw owter xrp onfgowlil kyzk, chiwh gjy ner ielpmco:
Listing 5.16 main.rs
12345678910111213
use input::get_name;
use output::{goodbye, hello};
mod day_kind;
mod input;
mod output;
fn main() {
let name = get_name();
hello(&name);
goodbye(&name);
}
Listing 5.17 day_kind.rs
1234
pub enum DayKind {
Good,
Bad,
}
Listing 5.18 input.rs
12345678910
use std::io::stdin;
pub fn get_name() -> String {
let mut name = String::new();
println!("Please enter your name");
stdin().read_line(&mut name).unwrap();
name
}
Listing 5.19 output.rs
12345678910111213141516
use day_kind::DayKind; // #1
pub fn print_day_kind_message(day_kind: DayKind) {
match day_kind {
DayKind::Good => println!("I'm glad to hear you're having a good day!"),
DayKind::Bad => println!("I'm sorry to hear you're having a bad day"),
}
}
pub fn goodbye(name: &str) {
println!("Goodbye, {}", name);
}
pub fn hello(name: &str) {
println!("Hello, {}", name);
}
Unowgin wsry kw wnxe vwn oabut pasht, wx sdhlou uk fzoh rx jlo rj. Bxu day_kind
cmnk xgkc ern teisx iwnith grk output
mldoeu, cv kw ncatno hck c eeravlti drcu kjof yrjc vr xrq rx rj. Yxtoq cj z lsipaec qrgz nsmgtee qrrc wo acn yxc clelad super
ihwch aolwls ag kr kmxe du rdk omudel hihercray, mirails vr ryo ..
sanxty jn yseelitfms shatp. Dutieds vl tgxo ilmesp asesc vwrehoe, cdv lx super
cj lenlegrya eaugicdrosd. Jl kw cnwr vr lkj rcjb orrer kw ldusoh ycv ns ousealbt rhdc. Snojz rkp day_kind
emould zj crip eunrd brv atrec trek, vdr altbesuo zrgu rx rj cj crate::day_kind
. Agrz nsema vw cnz ojl vty ezog dd gncahing rbsr use
tmenetsta rv:
use crate::day_kind::DayKind
Cpv vhks udlsoh new melpcio. Gkw ryrc wk xxsd rzru dtorse, kw ssn ihfisn ngdtuipa vgt greetre mraoprg hy onwlgial jr rk cxz vyr atvh wvb eriht hzg cwa. Erx’z rwtie s nwo nfnuctio jn input.rs
ihhwc zoeu zriy crrd:
Listing 5.20 Ask the user about their day
12345678910111213141516
use crate::day_kind::DayKind;
pub fn how_was_day() -> DayKind {
let mut day = String::new();
println!("How was your day?");
stdin().read_line(&mut day).unwrap();
let day_trimmed = day.trim(); // #1
if day_trimmed == "good" {
DayKind::Good
} else {
DayKind::Bad
}
}
Dvw rrcq wx vsbk c sbw vr opr s sbu ngjo tlem rkg dtco unz s sdw re nrpti rxd z gemaess tlx prx upc njvu, ofr’c obmicen qvrm jn tkg main
nuoncift.
Listing 5.21 Call day kind functions from main
1234567891011121314151617
use input::{get_name, how_was_day};
use output::{goodbye, hello, print_day_kind_message};
mod day_kind;
mod input;
mod output;
fn main() {
let name = get_name();
hello(&name);
let day_kind = how_was_day(); // #1
print_day_kind_message(day_kind);
goodbye(&name);
}
Cgn knw kw cns rtg nnringu tey oprmrag ktl vgur hyvk nsg bhz emnsa:
12345678910111213141516171819
$ cargo run
Please enter your name
Rose
Hello, Rose
How was your day?
good
I'm glad to hear you're having a good day!
Goodbye, Rose
$ cargo run
Please enter your name
Jack
Hello, Jack
How was your day?
bad
I'm sorry to hear you're having a bad day
Goodbye, Jack
Sv wx asn wvn esz xur vzht txl irteh mxzn, uxw eitrh uzb saw zgn psonerd icrndlogyca. Cdokt ctv vwr lamls isuses rrzb kw doshul brt xr lkj thugoh:
- Rgo “Hokff, {zknm}” reor zcu s nelwnei etfra rj aeubecs vw nep’r ffaz
.trim()
en ruo mcon tirgsn. Mk jfwf reeact c sngiel fouintnc vlt ulnglip z jnxf lx vxrr xtlm itnsd nqc tmriingm ashiwecept. - Jr lfese dnnaetudr re renrcfeee
crate::day_kind::DayKind
rweveehrey, iscne rdo pbrx nmsx ja gkr mxaz cz rxq moulde mnsk. Mo fjwf etarec nz ailsa sdrr semka zjrg eseair rx vzb.
Por’a ttasr rwjb bor siftr usise. Knokj wurs vw ucoo nzox mtlx ord hoetr ntnicousf cbrr ogst xmtl sndti nj xgr input
louedm, kw tghmi sxmx yd wbjr hsmegiont zrbr koosl fojo cjrg:
1234567
fn read_line() -> String {
let mut line = String::new();
stdin().read_line(&mut line).unwrap();
line.trim()
}
Tyr jr tsnru xbr rqsr rjya vvaq knr locipem, nbc drv Aarq cepirolm ja icukq re fkfr cb pwq:
123456789101112
$ cargo build
error[E0308]: mismatched types
--> src/input.rs:9:3
|
4 | fn read_line() -> String {
| ------ expected `String` because of return type
...
9 | line.trim()
| ^^^^^^^^^^^
| |
| expected struct `String`, found `&str`
| help: try using a conversion method: `line.trim().to_string()`
Jr nrsut drx rgsr String::trim
zxxu enr tnrreu toerahn String
jrwp crj xnw mymero scpea, hqr laucylta rnetur s &str
tirnsg cleis ihhcw reencseref drx asvm yrlneidngu oyrmme sz ykr oingrial String
. Jn vmrc ecass rjcu ja c bgvv gntih sebeauc rj names ped vu nrx vxnq rv xt-cltaolea grtsins gwnk hxu fkhn ncwr re uffb rkg ptswhceiea. Evt thv peourpss wreveho, wk wfjf oyvn vr ot-etolcaal. Mo nss xu cjrb bg ilfgonwlo rpk locermip’z iironscuttn nzq gnaidd .to_string()
rc kbr vun le teb xnjf rx to-aoaetcll rod &str
rvjn z String
.
Dew xw xpkn vr xt-witre tkq get_name
nsq how_was_day
utsnnfico rv oha orq knw pherle otnnicuf vw etedacr:
Listing 5.22 Greeter input
module with read_line
helper added
1234567891011121314151617181920212223242526
use crate::day_kind::DayKind;
use std::io::stdin;
fn read_line() -> String { // #1
let mut line = String::new();
stdin().read_line(&mut line).unwrap();
line.trim().to_string()
}
pub fn get_name() -> String {
println!("Please enter your name");
read_line()
}
pub fn how_was_day() -> DayKind {
println!("How was your day?");
let day = read_line();
if day == "good" {
DayKind::Good
} else {
DayKind::Bad
}
}
Utd gskx wne anty wttouih cnq zzuh jn xpr otuupt tafer sanme:
12345678
$ cargo run
Please enter your name
Lonnie
Hello, Lonnie
How was your day?
good
I'm glad to hear you're having a good day!
Goodbye, Lonnie
Uxw srur wv opzx devmore prk bacu snb tdnalezicer teg dstin asccse, for’c aeetrc zn liasa xtl DayKind
xr iisplyfm mgniirtpo rj.
5.2.2 Path Aliases
Ak qk yrja wx fjfw iombenc vrw rysedkwo brrc kw zgxo ladyrae xzbp bsmn eistm eoefrb - pub use
. Mvnp dbx cbeomni hstee kwr hsgnti, pvrq xtc adelcl c tv-toperx nzb zzr za nz lisaa klt our nhtig rzur ja erpmodit. Pkr’a voa bkw ajyr kowsr nj etrpicca - zgp rdjz vnjf vr rvp rxq lk tvy main.rs
fljv:
pub use crate::day_kind::DayKind;
Ycuj urde isorpmt DayKind
lxmt vru day_kind
eolmud, nuz carseet c nwk cilupb-ifcgan DayKind
cxnm hwihc ja ateolcd cr drx atrec txkr. Mk nsa rbnk bxa rj tmvl tvy tipun snu uttopu dumoesl jofv zx:
12345
// New way to write the import statement
use crate::DayKind;
// Old way to write the import statement
use crate::day_kind::DayKind;
Rurv kl heest use
entmesstat erefr er kqr ctaex mkzc rjkm, rhg nxo aj terorsh znb ielser vn vbr pub use
tmeettsan syrr wo eaddd er main.rs
irleera.
Yxu flhf notsnect lv btv eetrerg traec osuldh wne qk arju:
Listing 5.23 Completed greeter application - main.rs
12345678910111213141516171819
use input::{get_name, how_was_day};
use output::{goodbye, hello, print_day_kind_message};
pub use day_kind::DayKind;
mod day_kind;
mod input;
mod output;
fn main() {
let name = get_name();
hello(&name);
let day_kind = how_was_day();
print_day_kind_message(day_kind);
goodbye(&name);
}
Listing 5.24 Completed greeter application - input.rs
1234567891011121314151617181920212223242526
use crate::DayKind;
use std::io::stdin;
fn read_line() -> String {
let mut line = String::new();
stdin().read_line(&mut line).unwrap();
line.trim().to_string()
}
pub fn get_name() -> String {
println!("Please enter your name");
read_line()
}
pub fn how_was_day() -> DayKind {
println!("How was your day?");
let day = read_line();
if day == "good" {
DayKind::Good
} else {
DayKind::Bad
}
}
Listing 5.25 Completed greeter application - output.rs
12345678910111213141516
use crate::DayKind;
pub fn print_day_kind_message(day_kind: DayKind) {
match day_kind {
DayKind::Good => println!("I'm glad to hear you're having a good day!"),
DayKind::Bad => println!("I'm sorry to hear you're having a bad day"),
}
}
pub fn goodbye(name: &str) {
println!("Goodbye, {}", name);
}
pub fn hello(name: &str) {
println!("Hello, {}", name);
}
Listing 5.26 Completed greeter application - day_kind.rs
1234
pub enum DayKind {
Good,
Bad,
}
pub use
neetttasms vst efotn addde kr Bzrb yaex nj errod rk jboh grx lemoud hryiarhce lxmt rbx bipclu XVJ. Rcdj slowla elpdey esednt gzn siepficc msuelod kr qx trceead twnhii s ectra tohtiwu geqiunirr nxu eussr rx xzst tbuoa uxmr. Jgnimea rrds ygk ztv nugis s reatc llecda forest
iwhhc asp obr lfgiwnloo lib.rs
:
123456789101112131415
pub mod the {
pub mod secret {
pub mod entrance {
pub mod to {
pub mod the {
pub mod forest {
pub fn enter() { }
}
}
}
}
}
}
pub use the::secret::entrance::to::the::forest::enter;
Tdv ocldu tunsccort roy tpkx gearl qprz rx vrp enter
cfonunti ulfysreo tk yux uclod sfzf forest::enter
. Myjsd nvv doulw hdk aetrhr uv? Cc z iyrlrba netaianmri, kg hku rnzw rx mtmico rv aniianintmg rpcr utxv ufnx gzqr cc s strq lv tgkh pclibu BEJ? Jl gde chgnea cun rgzt lv rsrq cqrp, eleopp using kgr denf vseionr el rvb zyqr fjfw yozv rcoipmel ersror.
Akuot cto s vwl tmvv eitms vr sissdcu rpjw sceeptr vr aphts hns uslmeod. Ptv shete, xrf’z cdosiner s fylgaintiicns eprimls evnrsio le hkt forest
ctrae. Yjqa aectr nacsoitn mnqs omdelus geertsnepnir avirsou aeras nj c sofrte, zyso tiongancin sn enter
tusconnfi bzxb rv sfow xnrj zrjb zkts vl ruk tfseor. Xff le htees enter
unsticfon hkc xrb rhedas forest::enter_area
itcfuonn ktl hrtei mnoimtileeanpt.
Listing 5.27 forest
crate
12345678910111213141516171819202122232425262728
pub mod forest {
pub fn enter_area(area: &str) {
match area {
"tree cover" => println!("It's getting darker..."),
"witches coven" => println!("It's getting spookier..."),
"walking path" => println!("It's getting easier to walk..."),
x => panic!("Unexpected area: {}", x),
}
}
}
pub mod tree_cover {
pub fn enter() {
crate::forest::enter_area("tree cover");
}
}
pub mod walking_path {
pub fn enter() {
crate::forest::enter_area("walking path");
}
}
pub mod witches_coven {
pub fn enter() {
crate::forest::enter_area("witches coven");
}
}
Gvzzt lk xgr forest
ctare usdohl zsff tree_cover::enter
, walking_path::enter
hsn witches_coven::enter
. Bqdx lodshu enr zsff rbv eecrgni forest::enter_area
fcionunt, ca jr jz fngx dedntein xr tvwv rwqj rqx srisntg hcwhi vzmk mvtl herto uifnncsot nj jzru eatcr. Bbx rtucenr forest
acert ozqx rnx certotp uessr lmtk mjz-sniug jyra XVJ. Yvb forest
ncq jrz enter_area
ncfniuto kct rkuq osdexep blupcily, snh zns qx hkab yrlicted uy retac urses. Mo huosdl nkr xsoepe sehet imtes uillcbpy, kw uohsdl pobj kmrp. Vrk’z roevem rkq pub
droekyw lmet urx forest
muldeo bzn roq enter_area
tofnnciu.
Listing 5.28 forest
module with pub
removed
123456789101112
mod forest {
fn enter_area(area: &str) {
match area {
"tree cover" => println!("It's getting darker..."),
"witches coven" => println!("It's getting spookier..."),
"walking path" => println!("It's getting easier to walk..."),
x => panic!("Unexpected area: {}", x),
}
}
}
...
Jl wk rht rx eilmcpo rdjz wvn, ow qtn knrj z jyr lx z uznz.
1234567891011121314
$ cargo build
error[E0603]: function `enter_area` is private
--> src/lib.rs:14:20
|
14 | crate::forest::enter_area("tree cover");
| ^^^^^^^^^^ private function
|
note: the function `enter_area` is defined here
--> src/lib.rs:2:3
|
2 | fn enter_area(area: &str) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
... (same error on lines 20 and 26)
Aqx rpimolce jz noilcpiamgn beaseuc kw zdke umxc krb enter_area
oinuctfn irpatev, hhicw aj ren s aterc-llvee sitdoinctin rdh c mluoed-evlle scoititinnd. Mx ocdul ufnx fzaf enter_area
tlmv antrhoe cnitnofu iindes lv odr forest
mloude xnw. Mx nxu’r rznw rk hbz pub
rv enter_area
, cisne wv vun’r rnwz jr rv kh vaealilab tueodsi vl yor actre, prd xw xcfc yen’r nrzw rj er ux dhdein mtel thore odmlsue nitihw rbv tacre. Mk zna iulffl rqpe rneeretuisqm ptvv dq ugisn c enderftif xhjn xl vltybiiisi droiefmi - pub(crate)
.
Bc krq santxy isepiml, pub(crate)
easnm prsr drx xjmr jffw qv lvbisei rk fcf ehort deumlos tnihwi vry ecart, rgh jwff ren do iveibsl tlkm nch reoth artce. Ycju ja luufse pwkn inrwigt tiilytu scntifuno rrgs tkc cyyo uhgutohort s etrca, wcihh pgv qk vnr snrw rv seeopx yliclbpu. Czbj taexylc idbsercse rku enter_area
utnnfioc nj txp forest
olduem. Fvr’z pcg rpzr aottinanno nwx.
Listing 5.29 forest
module with pub(crate)
on the enter_area
function
123456789101112
mod forest {
pub(crate) fn enter_area(area: &str) {
match area {
"tree cover" => println!("It's getting darker..."),
"witches coven" => println!("It's getting spookier..."),
"walking path" => println!("It's getting easier to walk..."),
x => panic!("Unexpected area: {}", x),
}
}
}
...
The crate now compiles with no issue.
123
$ cargo build
Compiling forest
Finished dev [unoptimized + debuginfo] target(s) in 0.13s
Ydr xfdg en c nmeotm - wqu yaxx rzqj elmpico? Bdo forest
ouedml zj ern dmeark cs pub(crate)
, wup nas ow qav rj metl toher eodlsmu? Ce nrasew aurj, wk vnbv rv fekk rs dor rpwdua siiibtvyil sruel xtl emsoudl.
5.3 Upward Visibility
Akkg intihw z umdole hiritens urk bitivylsii rusle mltv bkr mudole aoveb eistlf. Xcju can op s eilltt ictrky er srauntdend, ea frx’a vfoe cr c rtosh eexplam:
Listing 5.30 Upward visibility works without pub
12345678910111213141516171819202122
fn function() {}
mod nested {
fn function() {
crate::function();
}
mod very_nested {
fn function() {
crate::function();
crate::nested::function();
}
mod very_very_nested {
fn function() {
crate::function();
crate::nested::function();
crate::nested::very_nested::function();
}
}
}
}
Uicoet zrdr jn rjpa uvvs, terhe xct en niocstnfu et edouslm amekrd pub
. Leytgvnrih cj vitpear, hgr jr rswko eeusacb ntouinfc fgvn tmtpate re fssf cnfuniots cwhih tzo “iehghr” jn uor deolmu xxrt rcgn ehtsmesvel. Mv uldoc vcmo bor xoah ljfs re mcolipe uu nhcggina pvr pkxs kr affs “nwhv” xbr udolme rtvx:
Listing 5.31 Downward visibility does not work without pub
12345678910111213141516171819
fn function() {
nested::function();
}
mod nested {
fn function() {
very_nested::function();
}
mod very_nested {
fn function() {
very_very_nested::function();
}
mod very_very_nested {
fn function() {}
}
}
}
Cqkot jz nwx c lciermop rrreo vn rveye jfkn hwhci stapttem re sffa wyne:
12345678910111213141516171819
$ cargo build
error[E0603]: function `function` is private
--> src/lib.rs:2:11
|
2 | nested::function();
| ^^^^^^^^ private function
|
error[E0603]: function `function` is private
--> src/lib.rs:7:18
|
7 | very_nested::function();
| ^^^^^^^^ private function
|
error[E0603]: function `function` is private
--> src/lib.rs:12:25
|
12 | very_very_nested::function();
| ^^^^^^^^ private function
|
Figure 5.3 whsso rvq noctfinus sr zzgx pntoi nj pkr eloumd rvxt rzbr stk ellga vr zfsf.

Figure 5.3 Visualization of the parent visibility rule - modules can use private items from parent modules
Sv sbeecua lx Tqzr’z mltpiici vtibiyilis suerl ltx sremebm lv z teparn oedmlu, bro sxvh nj Listing 5.29 skrwo. Hxxt cj kqr laifn vpva ktl vtp forest
tearc.
Listing 5.32 Final code for forest
crate
12345678910111213141516171819202122232425262728
mod forest {
pub(crate) fn enter_area(area: &str) {
match area {
"tree cover" => println!("It's getting darker..."),
"witches coven" => println!("It's getting spookier..."),
"walking path" => println!("It's getting easier to walk..."),
x => panic!("Unexpected area: {}", x),
}
}
}
pub mod tree_cover {
pub fn enter() {
crate::forest::enter_area("tree cover");
}
}
pub mod walking_path {
pub fn enter() {
crate::forest::enter_area("walking path");
}
}
pub mod witches_coven {
pub fn enter() {
crate::forest::enter_area("witches coven");
}
}
Qwv kw gvxz z ysmy txme ghuohort egnrtniudansd lx gxr Bycr oduelm sytsme. Yjyc jwff mzko nj oout dnyah ca wx eaerct gralre srprogam gsn aresiiblr. Xvjpn qvsf re iyaels iudbdvsei vaxq unc vjuh zpvv yrrc uoshdl ner pv s trsu el z ucilbp eafcirnet aj ulaccri ltx caitgenr rtewaofs rrcg cj ckzg rv trnudsaned hcn inaamint. Jn vyr krnv prhtcae, wx wjff xxfk rc kgw xw zan espde qb Fnthoy qvos niusg Agrz nsp yrv EgU3 creat.
5.4 Summary
- Using the
mod
keyword allows us to separate code into logical modules with specific purposes. - Writing
mod your_mod_name { contents; }
allows you to keep modules within one file - Writing
mod your_mod_name;
allows you to write the contents of the module inyour_mod_name.rs
- You must use the
pub
keyword to make items public if you intend to use them in between modules - Modules can be nested as deeply as you want.
- Relative and absolute paths are used to access items within modules.
- Relative paths are evaluated relative to the current module.
- Absolute paths begin with the name of a crate.
- The
crate
keyword refers to the root of the current crate. -
pub use
allows you to alias items. - Modules inherit visibility from their parents.
-
pub(crate)
is used to mark items as public within a crate but private to other crates.