Rust中的代码组织:package/crate/mod rust 百度百科

   2023-02-09 学习力0
核心提示:刚接触Rust遇到一堆新概念,特别是package, crate, mod 这些,特别迷糊,记录一下一、pakcage与crate当我们用cargo 创建一个新项目时,默认就创建了一个package,参考下面的截图:这样就生成了一个名为demo_1的package,另外也创建1个所谓的binary crate,当

刚接触Rust遇到一堆新概念,特别是package, crate, mod 这些,特别迷糊,记录一下

一、pakcage与crate

当我们用cargo 创建一个新项目时,默认就创建了一个package,参考下面的截图:
Rust中的代码组织:package/crate/mod

这样就生成了一个名为demo_1的package,另外也创建1个所谓的binary crate,当然也可以加参数 --lib生成library的crate

Rust中的代码组织:package/crate/mod

然后在crate里,又可以创建一堆所谓的mod(模块),因此整体的关系,大致象下面这张图:

Rust中的代码组织:package/crate/mod

即:

  • 1个Package里,至少要有1种Crate(要么是Library Crate,要么是Binary Crate)
  • 1个Package里,最多只能有1个Library Crate
  • 1个Package里,可以有0或多个Binary Crate
  • 1个Crate里,可以创建0或多个mod(后面还会详细讲mod)

 

二、crate的入口

通常在创建项目后,会默认生成src/main.rs,里面有1个main方法:

(base) ➜  code tree demo_1
demo_1
├── Cargo.toml
└── src
    └── main.rs

main.rs的内容:

fn main() {
    println!("Hello, world!");
}

这个就是crate运行时的入口函数,前面我们提过,1个package里,允许有1个library crate和多个binary crate,我们弄个复杂点的场景:

(base) ➜  demo_1 git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── lib.rs
    ├── main.rs
    └── main2.rs

在src里,再加2个文件lib.rs及main2.rs,内容如下:

lib.rs

pub fn foo(){
    println!("foo in lib");
}

main2.rs

fn main(){
    demo_1::foo();
    println!("hello 2");
}

同时把main.rs里也加一行demo_1::foo(),让它调用lib.rs里的foo()方法

fn main() { 
   demo_1::foo(); 
   println!("Hello, world!"); 
}

看上去,我们有2个main入口函数了,运行一下看看结果如何:

(base) ➜  demo_1 git:(master) ✗ cargo run
   Compiling demo_1 v0.1.0 (/Users/jimmy/code/demo_1)
    Finished dev [unoptimized + debuginfo] target(s) in 0.70s
     Running `target/debug/demo_1`
foo in lib
Hello, world!

从最后2行的输出来看,运行的是main.rs中的方法,即:main2.rs中的main函数,并未识别成入口,继续折腾,在src下创建目录bin,然后把main.rs以及main2.rs都移动到bin目录

(base) ➜  demo_1 git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── bin
    │   ├── main.rs
    │   └── main2.rs
    └── lib.rs

然后再运行: 

(base) ➜  demo_1 git:(master) ✗ cargo run  
error: `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key.
available binaries: main, main2

这次提示不一样了,大意是说有2个入口main, main2,不知道该运行哪一个,需要加参数明确告诉cargo,加1个参数 --bin main2

(base) ➜  demo_1 git:(master) ✗ cargo run --bin main2
   Compiling demo_1 v0.1.0 (/Users/jimmy/code/demo_1)
    Finished dev [unoptimized + debuginfo] target(s) in 0.62s
     Running `target/debug/main2`
foo in lib
hello 2

这样就可以了

 

三、 mod

3.1 定义mod

把main.rs里加点代码:

mod a {
    pub fn foo_a_1() {
        println!("foo_a_1");
    }

    fn foo_a_2(){
        println!("foo_a_2");
    }

    mod b {
        pub fn foo_b() {
            foo_a_2();
            println!("foo_b");
        }
    }
}

fn main() {
    a::foo_a_1();
    a::foo_a_2();
    a::b::foo_b();
}

解释一下:

  • 用mod关键字,定义了模块a,然后里面还嵌套了模块b
  • 然后在main方法里,尝试调用a模块的方法,以及其子模块b中的方法

编译一下,会发现各种报错:

-----------------------------------------------------

(base) ➜ demo_1 git:(master) ✗ cargo build
Compiling demo_1 v0.1.0 (/Users/jimmy/code/demo_1)
error[E0425]: cannot find function `foo_a_2` in this scope
--> src/bin/main.rs:12:13
|
12 | foo_a_2();
| ^^^^^^^ not found in this scope
|
help: consider importing this function
|
11 | use crate::a::foo_a_2;
|

error[E0425]: cannot find function `foo_a` in module `a`
--> src/bin/main.rs:19:8
|
19 | a::foo_a();
| ^^^^^ not found in `a`

error[E0603]: module `b` is private
--> src/bin/main.rs:20:8
|
20 | a::b::foo_b();
| ^ private module
|
note: the module `b` is defined here
--> src/bin/main.rs:10:5
|
10 | mod b {
| ^^^^^

Some errors have detailed explanations: E0425, E0603.
For more information about an error, try `rustc --explain E0425`.
error: could not compile `demo_1` due to 3 previous errors

-----------------------------------------------------

从提示上看,主要是private的问题:

  • 默认情况下Rust里的函数以及模块,都是private作用域的,外界无法访问,所以要改成pub

修改一下:

mod a {
    pub fn foo_a_1() {
        println!("foo_a_1");
    }

    //修改1:加pub
    pub fn foo_a_2(){
        println!("foo_a_2");
    }

    //修改2:加pub
    pub mod b {
        pub fn foo_b() {
            //修改3:调用父mod的方法,要加super关键字
            super::foo_a_2();
            println!("foo_b");
        }
    }
}

fn main() {
    a::foo_a_1();
    a::foo_a_2();
    a::b::foo_b();
}

再运行:

(base) ➜  demo_1 git:(master) ✗ cargo run
   Compiling demo_1 v0.1.0 (/Users/jimmy/code/demo_1)
    Finished dev [unoptimized + debuginfo] target(s) in 0.33s
     Running `target/debug/main`
foo_a_1
foo_a_2
foo_a_2
foo_b

正常了,但是这里可能有同学会疑问:mod a不也没加pub关键字吗,为啥main能正常调用?可以先记一条规则 :如果模块x与main方法在一个.rs文件中,且x处于最外层,main方法可以调用x中的方法

再微调下代码:

mod a {
    //修改:去掉pub
    fn foo_a_2(){
        println!("foo_a_2");
    }

    pub mod b {
        pub fn foo_b() {
            super::foo_a_2();
        }
    }
}

fn main() {
    a::b::foo_b();
}

再次运行:

(base) ➜  demo_1 git:(master) ✗ cargo run
   Compiling demo_1 v0.1.0 (/Users/jimmy/code/demo_1)
    Finished dev [unoptimized + debuginfo] target(s) in 0.42s
     Running `target/debug/main`
foo_a_2

疑问:父模块mod a中的foo_a_2没加pub,也就是默认private,为啥子模块b能调用?又是一条规则 :子模块可以调用父模块中的private函数,但是反过来是不行的 (通俗点讲:老爸的钱,就是儿子的钱,但是儿子的钱,除非儿子主动给老爸,否则还是儿子的!想必Rust的设计者们,深知“父爱如山”的道理)。

mod a {

    pub fn foo_a_1(){
        //这样是不行的,因为foo_b_2是private
        b::foo_b_2();
    }

    //修改:去掉pub
    fn foo_a_2(){
        println!("foo_a_2");
    }

    pub mod b {
        pub fn foo_b() {
            super::foo_a_2();
        }

        fn foo_b_2(){
            println!("foo_b_2");
        }
    }
}

fn main() {
    a::foo_a_1();
    a::b::foo_b();
}

这样会报错。

 

3.2 简化访问路径

前面介绍过,main.rs就是cargo的入口,也可以理解为cargo的根,所以就本文的示例而言:

    a::b::foo_b();
    self::a::b::foo_b();
    crate::a::b::foo_b();

是等效的,就好比,文件d:\a\b\1.txt,如果我们当前已经在d:\根目录下,
a\b\1.txt
d:\a\b\1.txt
.\a\b\1.txt
都能访问。

Rust中的代码组织:package/crate/mod

用全路径crate::a::b::foo_b()虽然能访问,但是代码看着太啰嗦了,可以用use来简化:

mod a {
    fn foo_a_2(){
        println!("foo_a_2");
    }

    pub mod b {
        pub fn foo_b() {
            super::foo_a_2();
        }      
    }
}

use crate::a::b::foo_b;

fn main() {
    use crate::a::b::foo_b as x;
    foo_b();
    x();
}

运行效果一样:

(base) ➜  demo_1 git:(master) ✗ cargo run
   Compiling demo_1 v0.1.0 (/Users/jimmy/code/demo_1)
    Finished dev [unoptimized + debuginfo] target(s) in 0.39s
     Running `target/debug/main`
foo_a_2
foo_a_2

从上面的示例可以看到:

  • use即可以在函数体内,也可以在函数外
  • 当2个模块的函数有重名时,可以用use .. as .. 来取个别名 

 

3.3 将mod拆分到多个文件

Rust中的代码组织:package/crate/mod

如上图,把mod a与b,分拆到a.rs, 及b.rs,与main.rs放在同1目录。注意main.rs的首二行:

mod a;
mod b;

与常规mod不同的是,mod x后,并没有{...}代码块,而是;号,rust会在同级目录下,默认去找x.rs,再来看main方法:

fn main() {
   a::a::foo_a_2();
   b::b::foo_b();
}

为何这里是a::a:: 连写2个a? 因为最开始声明mod a; 这里面已有1个模块a,而a.rs里首行,又定义了1个pub mod a,所以最终就是a::a::

如果mod太多,都放在一个目录下,也显得很乱,可以建个目录,把mod放到该到目录下:

(base) ➜  demo_1 git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── abc
    │   ├── a.rs
    │   ├── b.rs
    │   └── mod.rs
    └── main.rs

这时要在该目录下,新增1个mod.rs,用于声明该目录下有哪些模块

pub mod a;
pub mod b;

然后b.rs中引用a模块时,路径也要有所变化:

pub mod b {
    use crate::abc::a::a::foo_a_2;
    pub fn foo_b() {
        foo_a_2();
    }     
}

main.cs里也要相应调整:

mod abc;

fn main() {
   abc::a::a::foo_a_2();
   abc::b::b::foo_b();
}

目录abc,本身就视为1个mod,所以main.rs里的mod abc; 就是声明abc目录为1个mod,然后再根据abc/mod.rs,进一步找到a, b二个mod 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • bloom-server 基于 rust 编写的 rest api cache 中间件
    bloom-server 基于 rust 编写的 rest api cache
    bloom-server 基于 rust 编写的 rest api cache 中间件,他位于lb 与api worker 之间,使用redis 作为缓存内容存储, 我们需要做的就是配置proxy,同时他使用基于share 的概念,进行cache 的分布存储,包含了请求端口(proxy,访问数据) 以及cache 控制端口(
    03-08
  • #新闻拍一拍# Oracle 调研如何避免让 Java 开发者投奔 Rust 和 Kotlin | Linux 中国
    #新闻拍一拍# Oracle 调研如何避免让 Java 开发
     导读:• 英特尔对迟迟不被 Linux 主线接受的 SGX Enclave 进行了第 38 次修订 • ARM 支持开源的 Panfrost Gallium3D 驱动本文字数:977,阅读时长大约:1分钟作者:硬核老王Oracle 调研如何避免让 Java 开发者投奔 Rust 和 KotlinOracle 委托分析公司 Omd
    03-08
  • Linux系统下Rust快速安装:国内镜像加速
    Linux系统下Rust快速安装:国内镜像加速
    官方网址和方法Install Rust - Rust Programming Language然而速度慢得让人难以置信。利用国内镜像进行windows的Linux子系统的Rust安装。rust 使用国内镜像,快速安装方法参考:RUST安装慢怎么办,使用镜像方式安装_网络_为中华之崛起而编程-CSDN博客我的操作
    03-08
  • Rust到底值不值得学--Rust对比、特色和理念
    前言其实我一直弄不明白一点,那就是计算机技术的发展,是让这个世界变得简单了,还是变得更复杂了。当然这只是一个玩笑,可别把这个问题当真。然而对于IT从业者来说,这可不是一个玩笑。几乎每一次的技术发展,都让这个生态变得更为复杂。“英年早秃”已经成
    03-08
  • 超33000行新代码,为Linux内核添加Rust支持的补丁已准备就绪
    超33000行新代码,为Linux内核添加Rust支持的补
    https://mp.weixin.qq.com/s/oKw9aBJSdmRoO6-rbLAkNw7 月 4 日,一套修订后的补丁被提交至 Linux 内核的邮件列表中,该补丁为在 Linux 内核中以 Rust 作为辅助编程语言提供了支持,借助 Rust 可以提高 Linux 内核和内存的安全。整套补丁包含 17 个子项,不光
    03-08
  • 【译】Rust 的 Result 类型入门
    【译】Rust 的 Result 类型入门
    A Primer on Rust’s Result Type 译文原文链接:https://medium.com/@JoeKreydt/a-primer-on-rusts-result-type-66363cf18e6a原文作者:Joe Kreydt译文出处:https://github.com/suhanyujie/article-transfer-rs译者:suhanyujietips:水平有限,翻译不当之
    03-08
  • Rust实战系列-基本语法
    Rust实战系列-基本语法
    主要介绍 Rust 的语法、基本类型和数据结构,通过实现一个简单版 grep 命令行工具,来理解 Rust 独有的特性。本文是《Rust in action》学习总结系列的第二部分,更多内容请看已发布文章:一、Rust实战系列-Rust介绍“主要介绍 Rust 的语法、基本类型和数据结
    03-08
  • 全栈程序员的新玩具Rust(三)板条箱
    上次用到了stdout,这次我们来写一个更复杂一点的游戏rust的标准库叫做std,默认就会引入。这次我们要用到一个随机数函数,而随机数比较尴尬的一点是这玩意不在标准库中,我们要额外依赖一个库。很多编程方案都有自己的模块化库系统,rust也不例外,不过rust
    02-10
  • 全栈程序员的新玩具Rust(六)第一个WASM程序
    全栈程序员的新玩具Rust(六)第一个WASM程序
    先上代码https://gitee.com/lightsever/rust_study/tree/master/wasm_hello01webassembly就不用再赘述了,耳朵里面快磨出茧子来了。rustwasm是火狐自家的玩具,让我们来继续做实验,让rust飞起来吧。环境安装安装好rust环境之后仍然需要 一个 wasm 工具包carg
    02-10
  • 【Rust】标准库-Result rust数据库
    环境Rust 1.56.1VSCode 1.61.2概念参考:https://doc.rust-lang.org/stable/rust-by-example/std/result.html示例main.rsmod checked {#[derive(Debug)]pub enum MathError {DivisionByZero,NonPositiveLogarithm,NegativeSquareRoot,}pub type MathResult =
    02-09
点击排行