hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

Rust入坑指南:井井有条

2019-11-18杂谈搜奇网26°c
A+ A-

跟着我们的坑越来越多,越来越大,我们必须要对种种坑举行治理了。Rust为我们供应了一套坑务治理体系,轻易人人井井有条的寻觅、治理、填埋本身的种种坑。

Rust供应给我们一些治理代码的特征:

  • Packages:Cargo的一个特征,协助你举行构建、测试和同享crates
  • Crates:生成库或可实行文件的模块树
  • Modulesuse:用于掌握代码构造、局限和隐私途径
  • Paths:struct、function和module的定名要领

下面我们来细致看一下这些特征是怎样协助我们构造代码的。

Packages和Crates

package能够明白为一个项目,而crate能够明白为一个代码库。crate能够供多个项目运用。那我们的项目中package和crate是怎样定义的呢?

之前我们老是经由过程IDEA来新建项目,本日我们换个要领,在敕令行中运用cargo敕令来建立。

$ cargo new hello-world
     Created binary (application) `hello-world` package
$ ls hello-world
Cargo.toml
src
$ ls hello-world/src
main.rs

能够看到,我们运用cargo建立项目后,只要两个文件,Cargo.toml和src目次下的main.rs。

Cargo.toml是治理项目依靠的文件,每一个Cargo.toml定义一个package。main.rs文件的存在示意package中包括一个二进制crate,它是二进制crate的进口文件,crate的称号和package雷同。假如src目次下存在lib.rs文件,申明package中包括一个和package称号雷同的库crate。

一个package能够包括多个二进制crate,它们由src/lib目次下的文件定义。假如你的项目想援用别人的crate,能够在Cargo.toml文件中增添依靠。每一个crate都有本身的定名空间,因而假如你引入了一个crate内里定义了一个名为hello的函数,你依然能够在本身的crate中再定义一个名为hello的函数。

Module

Module协助我们在crate中构造代码,同时Module也是封装代码的重要东西。接下来照样经由过程一个栗子来细致相识Module。

前面我们说过,库crate定义在src/lib.rs文件中。这里起首建立一个包括了库crate的package:

cargo new --lib restaurant

然后在src中定义一些module和函数。

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

能够看到我们运用关键字mod来定义Module,Module中能够继承定义Module或函数。如许我们就能够比较轻易的把相干的函数放到一个Module中,并为Module定名,进步代码的可读性。别的Module中还能够定义struct和罗列。由于Module中能够嵌套定义子Module,终究我们定义出来的代码相似一个树形。

那末怎样接见Module中的函数呢?这就要提到Path了。这部份比较好明白,Module树相当于体系文件目次,而Path则是目次的途径。

Path

这里的途径和体系文件途径一样,都分为相对途径和绝对途径两种。个中绝对途径必需以crate开首,由于它代码悉数Module树的根节点。途径之间运用的是双冒号来示意援用。

如今我来尝试在一个函数中挪用add_to_waitlist函数:

能够看到这里不管用绝对途径照样相对途径都报错了,毛病信息是模块hosting和函数add_to_waitlist是私有(private)的。我们先临时放下这个毛病,依据这里的毛病提醒,我们晓得了当我们定义一个module时,默许状况下是私有的,我们能够经由过程这类要领来封装一些代码的完成细节。

OK,回到适才的题目,那我们怎样才处置惩罚这个毛病呢?地球人都晓得应当把对应的模块与函数公然出来。Rust中标识模块或函数为公有的关键字是pub

我们用pub关键字来把对应的模块和函数公然

如许我们就能够在module外来挪用module内的函数了。

Rust中的私有划定规矩

如今我们再回过甚来看Rust中的一些私有划定规矩,假如你实验了上面的例子,或许会有一些发明。

Rust中私有划定规矩适用于一切项(函数、要领、构造体、罗列、模块和常量),它们默许都是私有的。父模块中的项不能接见子模块中的私有项,而子模块中的项能够接见其祖辈(父模块及以上)中的项。

Struct和Enum的私有性

Struct和Enum的私有性略有差别,关于Struct来说,我能够只将个中的某些字段设置为公有的,其他字段能够依然坚持私有。

mod back_of_house {
    pub struct Breakfast {
        pub toast: String,
        seasonal_fruit: String,
    }

    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("peaches"),
            }
        }
    }
}

pub fn eat_at_restaurant() {
    // Order a breakfast in the summer with Rye toast
    let mut meal = back_of_house::Breakfast::summer("Rye");
    // Change our mind about what bread we'd like
    meal.toast = String::from("Wheat");
    println!("I'd like {} toast please", meal.toast);
}

而关于Enum,假如一个Enum是公有的,那末它的一切值都是公有的,由于私有的值没有意义。

相对途径和绝对途径的挑选

这类挑选不存在准确与否,只要是不是适宜。因而这里我们只是举例申明一些适宜的状况。

我们仍以上述代码为例,假如我们能够预见到今后须要把front_of_house模块和eat_at_restaurant函数移动到一个新的名为customer_experience的模块中,就应当运用相对途径,如许我们就对其举行调解。

相似的,假如我们须要把eat_at_restaurant函数移动到dining模块中,那末我们挑选绝对途径的话就不须要做调解。

综上,我们须要对代码的优化方向有一些前瞻性,并以此来推断须要运用相对途径照样绝对途径。

相对途径除了以当前模块开首外,还能够以super开首。它示意的是父级模块,相似于文件体系中的两个点(..)。

use关键字

绝对途径和相对途径能够协助我们找到指定的函数,但用起来也异常的贫苦,每次都要写一大长串途径。还好Rust为我们供应了use关键字。在许多言语中都有import关键字,这里的use就有些相似于import。不过Rust会供应越发雄厚的用法。

use最基本的用法就是引入一个途径。我们就能够越发轻易的运用这个途径下的一些要领:

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

这个途径能够是绝对途径,也能够是相对途径,但假如是相对途径,就必须要以self开首。上面的例子能够写成:

use self::front_of_house::hosting;

这与我们前面讲的相对途径好像有些抵牾,Rust官方说会在以后的版本处置惩罚这个题目。

use还能够更进一步,直接指向细致的函数或Struct或Enum。但习气上我们运用函数时,use背面运用的是途径,如许能够在挪用函数时晓得它属于哪一个模块;而在运用Struct/Enum时,则细致指向它们。固然,这只是官方发起的编程习气,你也能够有本身的习气,不过最好照样根据官方引荐或者是项目商定的范例比较好。

关于统一途径下的某些子模块,在引入时能够合并为一行,比方:

use std::io;
use std::cmp::Ordering;
// 等价于
use std::{cmp::Ordering, io};

偶然我们还会碰到援用差别包下雷同称号Struct的状况,这时候有两种处置惩罚办法,一是不指定到细致的Struct,在运用时加上差别的途径;二是运用as关键字,为Struct起一个别号。

要领一:

use std::fmt;
use std::io;

fn function1() -> fmt::Result {
    // --snip--
}

fn function2() -> io::Result<()> {
    // --snip--
}

要领二:

use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
    // --snip--
}

fn function2() -> IoResult<()> {
    // --snip--
}

假如要导入某个途径下的悉数模块或函数,能够运用*来示意。固然我是异常不发起运用这类要领的,由于导入悉数的话,假如涌现称号争执就会很难排查题目。

关于外部的依靠包,我们须要先在Cargo.toml文件中增加依靠,然后就能够在代码中运用use来引入依靠库中的途径。Rust供应了一些规范库,即std下的库。在运用这些规范库时是不须要增加依靠的。

有些同砚看到这里能够要最先埋怨了,说好了引见怎样拆分文件,到如今照样在一个文件里玩,这不是诳骗读者嘛。

别急,这就最先拆分。

最先拆分

我们拿适才的一段代码为例

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

起首我们能够把front_of_house模块下的内容拆分出去,须要在src目次下新建一个front_of_house.rs文件,然后把front_of_house模块下的内容写到文件中。lib.rs文件中,只须要声明front_of_house模块即可,不须要细致的定义。声明模块时,将花括号即内容改成分号就能够了。

mod front_of_house;

然后我们能够继承拆分front_of_house模块下的hosting模块和serving模块,这时候须要新建一个名为front_of_house的文件件,在该文件夹下安排要拆分的模块的同名文件,把模块定义的内容写在文件中,front_of_house.rs文件一样只保存声明即可。

拆分后的文件目次如图

本文重要讲了Rust中Package、Crate、Module、Path的观点和用法,有了这些基本,我们背面才有能够开辟一些比较大的项目。

ps:本文的代码示例均来自the book。

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
Rust入坑指南:井井有条

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282289.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>