Rust Ability Development (7): Manager and Module

image

 

Preface

 

The previous 6 texts introduced the basic features of Rust in general, and gave you a taste of the language's type system. Based on this, I believe that readers can write some basic programs by themselves, but this is not enough. We need to continue to upgrade and gradually enter the level of practical projects.

 

In work, programs are often composed of files, and there are dependencies between them, compilation, linking, etc. are not very simple things, and the complexity involved must be managed. Especially for large projects, manual management has become impossible. Fortunately, there are powerful project management tools in the Rust world.

 

So, in this chapter these articles will introduce how Rust manages large projects and the characteristics of related project management tools . Specifically, the following topics are covered:

 

  • Package manager

  • Module

  • Cargo project manager and crate as compilation unit

  • Create and build the project

  • Run a simple test

  • Cargo subcommands and installation of third-party package crates

  • Project practice

 

This article first introduces

  • Package manager

  • Module

 

Package manager

 

The actual code is usually multi-file and multi-dependent, so good management tools are needed to ensure that the organization is always clear. For friends who use Python or R, they should check the various updates involved in the management tools of their respective Packages. For relatively low-level languages ​​like C or C++, there is no default package manager , and the GNU make tool is mainly used . The language of this tool is obscure and vague, and it is often necessary to manually add header files. There is no built-in third-party download The package tool is not convenient for long-term large-scale project management.

 

So, fortunately, Rust is not like this. It has a practical package management tool, Cargo , which can deal with sufficiently complex situations and is easy to create and maintain project code. This is the core of this article.

 

 

Module

 

As a basis for understanding the Package Manager, we will first introduce the modules in Rust in a little detail and see how the code is organized.

Every Rust program starts with the root module:

 

  • Create a library, the root module is the lib.rs file.

  • Create an executable file. The root module is any file with a main function, usually main.rs.

 

When the code swells, in order to provide flexibility in organizing the project, it can be divided into modules. There are many ways to create it.

 

 

Nested modules

 

The easiest way to create a module is to use the mod() block in an existing module, look at the following code

// mod_within.rs
mod food {
   
       struct Cake;    struct Smoothie;    struct Pizza;}
//use food::Cake;
fn main() {
   
       let eatable = Cake;}

 

Here we have built an internal module named food. Inside the braces, we declare three structures, Cake, Smoothie , and Pizza ;

In main, we create an instance of make. The code result is as follows:

 

image

 

Obviously, the compiler doesn't know the definition of Cake. At this time, add the use food::Cake; statement, compile it again, and see the result, as shown below

image

The original error is gone, but I got another error here, mentioning that Cake is private, here is another important feature of the module, the default private setting. If you need to visit, you need two steps:

 

  • Add the pub keyword before the declared variable of the module

  • Add food::Cake

 

Change to the following​​​​​​​

// mod_within.rs
mod food {
   
       pub struct Cake;  //pub    struct Smoothie;    struct Pizza;}
use food::Cake;
fn main() {
   
       let eatable = Cake;}

 

The code result is as follows,

image

 

Although I got 3 warnings, it still passed the compilation. Some readers may have asked why such a nested module is defined. The reason and usage will be introduced in the detailed code test (Chapter 3).

 

File as a module (File as a moule)

Like the title, the module can be created as a file. Directly on the example, here I will create a directory with the following structure.

image

 

In foo.rs contains a structure Bar, and its realization impl content, the code is as follows:​​​​​​​

// modules_demo/foo.rs
pub struct Bar;
impl Bar {
   
       pub fn init() {
   
           println!("Bar type initialized");    }}

At this time, we hope to use this module in main.rs, then the code is as follows:​​​​​​​

// modules_demo/main.rsmod foo;
use crate::foo::Bar;
fn main() {
   
       let _bar = Bar::init();}

The code result is as follows,

image

 

Looking at the main.rs code, we first declare the module foo. Then I imported foo. The format involved here is use crate::foo::Bar. One thing to talk about is that the prefix used here is crate . I don’t know if readers still have an impression. Crate refers to file packages or library files in rust. Let's see what is meant here.

 

Generally speaking, in rust, there are three main prefixes needed to import modules:

 

  • Absolute imports : absolute path

    • Crate , starting from the root node, import files at the same level as the current file.

  • Relative imports: relative path

    • self : start from the current module

    • Super : Start from the upper level module

 

Directory as a module (Directory as a moule)

 

Taking a directory as a module means that the structure is hierarchical, and we can create sub-module files or more directory levels in it. Imagine a situation: we have a directory my_program, which has a module named foo as a file foo.rs, which contains a type named Bar and functions of foo. As time goes by, the number of Bar APIs is increasing, and we hope to separate them into a sub-module. At this time, the content of the directory as the module is involved.

 

So let's implement it in code. First create a directory, with an entry point in main.rs, and add a directory named foo.rs, which now contains a submodule named bar.rs, as shown below :

image

 

In order for Rust to know bar, we also need to create a file named foo at the same level as the foo directory. The foo.rs file will contain the mod declarations of any submodules (here bar.rs) created in the foo directory.

 

Let's look at the content of the bar.rs file:​​​​​​​

//bar.rs
pub struct Bar;
impl Bar {
   
       pub fn hello() {
   
           println!("Hello from Bar !");    }}

 

Here is a cell structure Bar with a related method hello, we will use this API in main.rs. Next, look at the foo.rs file:​​​​​​​

//foo.rs
mod bar;
pub use self::bar::Bar;
pub fn do_foo() {
   
       println!("Hi from foo!");}
  • On line 3 we added a module declaration.

  • Import the module bar, and import the keyword self, which indicates that it is imported from the module itself. Here, Bar is defined as pub to ensure that the content of the submodule can be used by the parent module. This is a very convenient way of writing, and the reason will not be revealed until later chapters.

 

Finally, we look at the main.rs file:​​​​​​​

// my_program/main.rs
mod foo;
use foo::Bar;
fn main() {
   
       foo::do_foo();    Bar::hello();}

The code results are as follows:

image

It can be seen that the program ran through.

 

Conclusion

 

After introducing the Package Manager, this article focuses on the content of the modules in rust, and the relevant examples are for readers to have a basic understanding of how to use the modules as the basis for subsequent learning content.

 

The next article will introduce Cargo and Crates .

 

Guess you like

Origin blog.csdn.net/qq_40433634/article/details/113073924