Rust modules: Difference between revisions

From wikinotes
 
(28 intermediate revisions by the same user not shown)
Line 5: Line 5:
<blockquote>
<blockquote>
{| class="wikitable"
{| class="wikitable"
|-
| official docs || https://doc.rust-lang.org/reference/items/modules.html
|-
|-
| cargo book: package layout || https://doc.rust-lang.org/cargo/guide/project-layout.html
| cargo book: package layout || https://doc.rust-lang.org/cargo/guide/project-layout.html
Line 20: Line 22:
</blockquote><!-- Tutorials -->
</blockquote><!-- Tutorials -->


= Scrap =
= Examples =
<blockquote>
<blockquote>
The core idea is that <code>main.rs/lib.rs</code> must import all paths.
The core idea is that <code>main.rs/lib.rs</code> must directly/indirectly import all paths.


* <code>mod</code> allows access to namespace,<br>using namespace,<br>for modules in same-directory<br>(ex. <code>./my_module.rs</code>, <code>./my_module/mod.rs</code>)
* <code>crate</code> is the root namespace of the crate
* <code>use</code>
* <code>mod</code> allows access to a namespace, using namespace prefix, for modules in same-directory
* <code>use</code> merges a namespace (or elements from it) into the current namespace
* <code>pub mod</code> exposes module externally
* <code>super</code>, within <code>use/mod</code> refers to the parent scope


== sample-1: (kwd mod) use module from namespace ==
== sample-1: (mod) use module from namespace ==
<blockquote>
<blockquote>
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 62: Line 67:
</blockquote><!-- sample-1 -->
</blockquote><!-- sample-1 -->


== sample-2 (kwd mod) use file from module ==
== sample-2 (mod) use file from submodule ==
<blockquote>
<blockquote>
In order to use <code>street::lamps::*</code> from <code>main.rs</code>,<br>
we must publish <code>lamps</code> from street.
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
src/
src/
Line 110: Line 118:
}}
}}
</blockquote><!-- sample-2 -->
</blockquote><!-- sample-2 -->
</blockquote><!-- Scrap -->


= Entrypoint =
== sample-3 (use) use file from submodule ==
<blockquote>
<blockquote>
For modules to be compiled, they must be used (however indirectly)<br>
In order to use <code>street::lamps::*</code> from <code>main.rs</code>,<br>
from either your crate's <code>main.rs</code> or <code>lib.rs</code>.
we must publish <code>lamps</code> from street.
 
<syntaxhighlight lang="bash">
src/
  street/
    mod.rs
    lamps.rs
  main.rs
</syntaxhighlight>
 
{{ expand
| <code>src/main.rs</code>
|
<syntaxhighlight lang="rust">
mod street;
use street::lamps::*;
 
fn main() {
    println!("{}", brightness());
}
</syntaxhighlight>
}}
 
{{ expand
| <code>src/street/mod.rs</code>
|
<syntaxhighlight lang="rust">
// src/street/mod.rs
 
pub mod lamps;
</syntaxhighlight>
}}
 
{{ expand
| <code>src/street/lamp.rs</code>
|
 
<syntaxhighlight lang="rust">
// src/street/lamp.rs


</blockquote><!-- Entrypoint -->
pub fn brightness() -> isize {
    100
}
</syntaxhighlight>
}}
</blockquote><!-- sample-3 (kwd use) -->


= Naming/Paths =
== sample-4 use lib.rs from main.rs ==
<blockquote>
<blockquote>
Module names govern where they can be found within the filesystem.<br>
When building executables, it's customary for most of the business-logic to live in <code>lib.rs</code>,<br>
Module locations are based on where they are defined
with a tiny skeleton program in <code>main.rs</code>.


<pre>
Code from <code>lib.rs</code> will be imported from your project-name's namespace.
# from the rust book:
backyard
├── Cargo.lock
├── Cargo.toml
└── src
    ├── garden
    │  └── vegetables.rs
    ├── garden.rs
    └── main.rs
</pre>


The module <code>foo</code>'s code could be
<syntaxhighlight lang="rust">
* <code>src/foo.rs</code>
// main.rs
* <code>src/foo/mod.rs</code>
 
</blockquote><!-- Naming/Paths -->
use my_project;  // code from `lib.rs`
 
fn main() {
    my_project::some_function();
}
</syntaxhighlight>
</blockquote><!-- sample-4 use lib.rs from main.rs -->
</blockquote><!-- Examples -->
 
= Entrypoints =
<blockquote>
For modules to be compiled, they must be used (however indirectly) from their crate-root (build target).<br>
By default these are:
* <code>src/main.rs</code> for executables
* <code>src/lib.rs</code> for libraries (imported as the package-name)
 
See [[rust anatomy]] for more details.
</blockquote><!-- Entrypoints -->


= Imports =
= Imports =
<blockquote>
<blockquote>
* <code>use</code> merge namespace into current (ex. <code>use foo; myfn();</code>)
* <code>use</code> merge namespace into current (ex. <code>use foo; myfn();</code>)
* <code>use as</code> lets you alias a namespace
* <code>mod</code> enables you to access from namespace (ex. <code>mod foo; foo::myfn();</code>)
* <code>mod</code> enables you to access from namespace (ex. <code>mod foo; foo::myfn();</code>)


Line 152: Line 210:
use std::fs::File;                // import 'File' only into current namespace
use std::fs::File;                // import 'File' only into current namespace
use std::fs::{File, DirBuilder};  // import multiple types/functions into current namespace
use std::fs::{File, DirBuilder};  // import multiple types/functions into current namespace
use std::fs as fs                // within this namespace, refer to 'std::fs' as 'fs'


std::io::stdin()                  // you also can access objects directly from their namespace without `use`
std::io::stdin()                  // you also can access objects directly from their namespace without `use`
</syntaxhighlight>
</syntaxhighlight>


<code>mod</code> (access namespace)
<code>mod</code> enables access to submodules, 1-level deep, from current module.
<syntaxhighlight lang="rust">
<syntaxhighlight lang="rust">
 
// expose ./foo.rs or ./foo/mod.rs from current module
pub mod foo;
</syntaxhighlight>
</syntaxhighlight>
</blockquote><!-- Imports -->
</blockquote><!-- Imports -->
Line 165: Line 225:
<blockquote>
<blockquote>
By default, a module's code is public to itself and it's children,<br>
By default, a module's code is public to itself and it's children,<br>
but private to it's parents and/or callers.
but private to it's parents and/or callers.<br>
The <code>pub</code> keyword exposes a module/function.
 
* parents modules can expose access to their children with <code>pub mod ${foo}</code>
* child modules can access their parents without importing them using <code>super::</code>
* child modules can use absolute paths to symbols, from the <code>crate::</code> namespace
* imports are private by default, unless you import using <code>pub use some::module</code>


<syntaxhighlight lang="rust">
See [[rust access control]] for more details.
pub mod house {
    pub mod livingroom {
        // ...
    }
    mod bedroom {
        // ...
    }
}
</syntaxhighlight>
</blockquote><!-- Access Control -->
</blockquote><!-- Access Control -->

Latest revision as of 03:22, 9 February 2023

Modules are rust libraries.
The std::prelude module is included in the scope of every program.

Documentation

official docs https://doc.rust-lang.org/reference/items/modules.html
cargo book: package layout https://doc.rust-lang.org/cargo/guide/project-layout.html

Tutorials

rust module system https://www.sheshbabu.com/posts/rust-module-system/

Examples

The core idea is that main.rs/lib.rs must directly/indirectly import all paths.

  • crate is the root namespace of the crate
  • mod allows access to a namespace, using namespace prefix, for modules in same-directory
  • use merges a namespace (or elements from it) into the current namespace
  • pub mod exposes module externally
  • super, within use/mod refers to the parent scope

sample-1: (mod) use module from namespace

src/
  main.rs
  house.rs

src/main.rs

// main.rs

mod house;

fn main() {
    println!("{}", house::house_name());
}

house.rs / house/mod.rs

// house.rs  /  house/mod.rs

pub fn house_name() -> String {
    String:from("hi")
}

sample-2 (mod) use file from submodule

In order to use street::lamps::* from main.rs,
we must publish lamps from street.

src/
  main.rs
  street/
    mod.rs
    lamps.rs

main.rs

// main.rs

mod street;

fn main() {
    printlnt("{}", street::lamps::brightness());
}

street/mod.rs


// street/mod.rs

pub mod lamps;

street/lamps.rs


// street/lamps.rs

pub fn brightness() -> isize {
    100
}

sample-3 (use) use file from submodule

In order to use street::lamps::* from main.rs,
we must publish lamps from street.

src/
  street/
    mod.rs
    lamps.rs
  main.rs

src/main.rs

mod street;
use street::lamps::*;

fn main() {
    println!("{}", brightness());
}

src/street/mod.rs

// src/street/mod.rs

pub mod lamps;

src/street/lamp.rs


// src/street/lamp.rs

pub fn brightness() -> isize {
    100
}

sample-4 use lib.rs from main.rs

When building executables, it's customary for most of the business-logic to live in lib.rs,
with a tiny skeleton program in main.rs.

Code from lib.rs will be imported from your project-name's namespace.

// main.rs

use my_project;  // code from `lib.rs`

fn main() {
    my_project::some_function();
}

Entrypoints

For modules to be compiled, they must be used (however indirectly) from their crate-root (build target).
By default these are:

  • src/main.rs for executables
  • src/lib.rs for libraries (imported as the package-name)

See rust anatomy for more details.

Imports

  • use merge namespace into current (ex. use foo; myfn();)
  • use as lets you alias a namespace
  • mod enables you to access from namespace (ex. mod foo; foo::myfn();)

use (merge with current namespace)

use std::io;                      // merges objects from namespace into your own
use std::io::*;                   //
use std::fs::File;                // import 'File' only into current namespace
use std::fs::{File, DirBuilder};  // import multiple types/functions into current namespace
use std::fs as fs                 // within this namespace, refer to 'std::fs' as 'fs'

std::io::stdin()                  // you also can access objects directly from their namespace without `use`

mod enables access to submodules, 1-level deep, from current module.

// expose ./foo.rs or ./foo/mod.rs from current module
pub mod foo;

Access Control

By default, a module's code is public to itself and it's children,
but private to it's parents and/or callers.
The pub keyword exposes a module/function.

  • parents modules can expose access to their children with pub mod ${foo}
  • child modules can access their parents without importing them using super::
  • child modules can use absolute paths to symbols, from the crate:: namespace
  • imports are private by default, unless you import using pub use some::module

See rust access control for more details.