1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
//! Modularize this!
//!
//! - **Date:** November 16, 2015
//! - **Subject:** Designing APIs, and using packages ("crates") and modules
//! - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e006.mp3
//!
//! <audio style="width: 100%" title="Modularize this!" controls preload=metadata src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e006.mp3"></audio>
//!
//! # Notes
//!
//! Today, we are talking about modules, packages, and APIs in Rust. Taking a
//! bit of a breather after some pretty hard material the last few weeks.
//!
//! For reference, the [Rust book][notes-1] section on [Crates and
//! Modules][notes-2] will be very helpful.
//!
//! [notes-1]: http://doc.rust-lang.org/book/
//! [notes-2]: http://doc.rust-lang.org/book/crates-and-modules.html
//!
//! ## Corrigenda
//!
//! I accidentally called this episode 5, instead of episode 6. *Whoops.*
//!
//! Just before the 15:00 mark, while discussing libraries, I referred to
//! "e006.md" when I meant to say "e006.rs". Slips of the tongue inspired by the
//! fact that Rust (delightfully) uses Markdown for its documentation.
//!
//! # Links
//!
//! - [Roguelike in Rust][links-1]
//! - [Yehuda Katz on Ruby FFI][links-2]
//!
//! [links-1]: http://jaredonline.svbtle.com/roguelike-tutorial-table-of-contents
//! [links-2]: https://engineering.intercom.io/yehuda-on-rust-with-ruby/
//!
//! # Module Docs!
//!
//! As you've no doubt noted if you've actually looked at the show notes along
//! the way, these are in fact module docs! Because we're inside a module marked
//! off by being a file, we *have* to use the `//!` style of documentation
//! comments to mark them off. However, as you'll see below, if we structure or
//! declare modules in other ways, we will not have the same restriction.
//!
//! # Sponsors
//!
//! - reddraggone9
//! - [Chris Patti][sponsors-1]
//!
//! [sponsors-1]: http://podcastinit.com
//!
//! ## Become a sponsor
//!
//! - <a href="https://www.patreon.com/newrustacean" rel="payment">Patreon</a>
//! - [Venmo](https://venmo.com/chriskrycho)
//! - [Dwolla](https://www.dwolla.com/hub/chriskrycho)
//! - [Cash.me](https://cash.me/$chriskrycho)
//!
//! # Follow
//!
//! - New Rustacean:
//! + Twitter: [@newrustacean](https://www.twitter.com/newrustacean)
//! + App.net: [@newrustacean](https://alpha.app.net/newrustacean)
//! + Email: [hello@newrustacean.com](mailto:hello@newrustacean.com)
//! - Chris Krycho
//! + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)
//! + App.net: [@chriskrycho](https://alpha.app.net/chriskrycho)
/// This is an internal module. Note that it isn't public.
///
/// Modules may have any kind of "item" local to them. "Items" in Rust are
/// things like functions, structs, enums, traits, type definitions, and other
/// modules.
///
/// Modules have namespaces
mod internal_module {
/// A module function, demonstrating module-public function status.
///
/// This function is public to the `internal_module`, but because the module
/// itself isn't public, neither is the function. It is available to
/// anything which uses `internal_module`, however, as it is public at the
/// function level.
pub fn a_public_module_fn() {
println!("At `internal_module::a_public_module_fn()`.");
a_private_module_fn();
}
/// Another module function, demonstrating module-private function status.
///
/// Since this function is private to the module, it is inaccessible to
/// external callers (see below in `use_modules_internal()`). However, it is
/// accessible as normal to other functions within its own module, and thus
/// can be called by `a_public_module_fn()`.
fn a_private_module_fn() {
println!("At `internal_module::a_private_module_fn()`.");
}
}
/// This is an internal module which *is* public.
///
/// External modules therefore have access to this module, not just other
/// modules within the immediate parent `e006` (file) module.
pub mod public_internal_module {
/// A public function in a public module.
///
/// Note that the name of this function is the *same* as the public function
/// in `internal_module` above! This is one of the values of namespacing.
pub fn a_public_module_fn() {
println!("At `public_internal_module::a_public_module_fn()`.");
some_private_fn();
}
/// A private function in a public modules.
fn some_private_fn() {
println!("At `public_internal_module::some_private_fn()`.");
}
}
/// Demonstrates the use of modules and namespaces.
///
/// Modules can access other modules which are contained in the same parent
/// module as them regardless of the privacy settings. However, they cannot
/// access non-public modules which don't have the same immediate parent.
pub fn use_modules_internal() {
println!("At `use_modules_internal()`.");
// Calling another module's function is quite straightforward.
internal_module::a_public_module_fn();
// Note that we cannot access the internal module's private function. If you
// uncomment the following line, you will see a compile error indicating
// that the function is private.
//
// internal_module::a_private_module_fn();
//
// Similarly, as you would expect, we have access to public functions in
// public modules, but no access to private functions in public modules. (We
// have already seen this, in fact, just in file-based, rather than
// declaration-based, modules.)
public_internal_module::a_public_module_fn();
}
// What if we wanted to use *any* public function from a given module? We
// can simply `use` that module.
//
// It is worth quoting the Rust book here:
//
// > **Note:** Unlike in many languages, use declarations in Rust do not
// > declare linkage dependency with external crates. Rather, `extern crate`
// > declarations declare linkage dependencies.
pub mod demonstrate_namespacing {
/// We can `use` other module's contents.
use crate::e006::public_internal_module::*;
/// We can also alias other modules. Note that though we don't use this
/// until `demonstrate_aliased_calls()`, we have to put any `use` statements
/// before any other contents of the module (so this can't go between the
/// `demonstrate_globbed_calls()` and `demonstrate_aliased_calls()` function
/// definitions).
use crate::e006::internal_module as im;
/// Demonstrates how glob-imported `use`s works.
pub fn demonstrate_globbed_calls() {
println!("At `demonstrate_namespacing::demonstrate_globbed_calls()`.");
// Having imported *everything* from `public_internal_module`, we can call
// its public functions directly.
a_public_module_fn();
}
/// Demonstrates how aliased namespaces work.
pub fn demonstrate_aliased_calls() {
println!("At `demonstrate_namespacing::demonstrate_aliased_calls`.");
im::a_public_module_fn();
}
}
/// Demonstrates that modules can be `use`d within functions.
pub fn demonstrate_use_inside_function() {
use crate::e006::demonstrate_namespacing as dn;
println!("At `demonstrate_use_inside_function()`.");
dn::demonstrate_globbed_calls();
}
/// Give an example of nested modules.
///
/// Of course, *all* the modules in this file are nested: they are part of the
/// file-level `e006` module. Here, though, we see an explicit example of that.
pub mod demonstrate_nesting {
/// This is just a nested module.
pub mod a_nested_module {}
// An example of re-exporting another module's contents publicly.
//
// Remember, this module was initially part of a private module (but one
// within the `e006` parent module, and therefore accessible to us.)
// We are re-exporting its `a_nested_module` contents, with a different
// name, as a public module. When you look at the docs, you'll see this
// function name within the module, with the docs from the definition of the
// function in the `internal_module` above!
pub use crate::e006::internal_module::a_public_module_fn as now_public_fn;
}