Rust包管理与错误处理

文章目录

包管理

Rust的包管理有三个重要的概念,分别是箱、包、模块

箱(Crate)

这个Crate是二进制程序文件或者是苦文件,存在于包中

是树状结构,树根是编译器开始运行时编译的源文件所编译的程序

二进制程序文件不一定是可执行文件,只能确定是包含沐白哦机器语言的文件,文件格式主要取决于编译环境

包(Package)

我们使用cargo new一个Rust工程时,这个工程其实就是一个包,包必须由Cargo.toml文件来管理,主要是描述包的基本信息和依赖项

一个包最多包含一个库Crate,但是可以包含任意二进制Crate,但是至少包含一个Crate

当我们创建完项目之后,会有一个main.rs,这其实就意味着这是一个二进制项目

模块(Module)

Rust中组织的单位是模块,模块有很多中声明方式

例如

rust 复制代码
mod nation {
    mod government {
        fn govern() {}
    }
    mod congress {
        fn legislate() {}
    }
    mod court {
        fn judicial() {}
    }
}

用树形图表示就是

shell 复制代码
nation
 ├── government
 │ └── govern
 ├── congress
 │ └── legislate
 └── court
   └── judicial

Rust中描述目录结构是使用::

从根目录(crate)开始的绝对路径是crate::nation::government::govern();,也可以使用相对路径nation::government::govern();

访问权限

Rust中只有两种访问权限,publicprivate

默认是private的,要设置为公有,则需要设置pub关键字,例如

rust 复制代码
mod nation {
    pub mod government {
        pub fn govern() {}
    }

    mod congress {
        pub fn legislate() {}
    }
    
    mod court {
        fn judicial() {
            super::congress::legislate();
        }
    }
}

fn main() {
    nation::government::govern();
}

对于结构体来说,结构体本身也可以加上pub,能让外部访问,但是其字段依旧是私有的,如果想要访问,也需要pub来声明

rust 复制代码
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() {
    let mut meal = back_of_house::Breakfast::summer("Rye");
    meal.toast = String::from("Wheat");
    println!("I'd like {} toast please", meal.toast);
}
fn main() {
    eat_at_restaurant()
}

在Rust中,每一个文件其实就相当于一个模块

use关键字

use关键字其实就相当于一种简便写法,可以将模块中的函数导入到当前文件,也可以使用as起一个别名

例如

rust 复制代码
mod nation {
    pub mod government {
        pub fn govern() {}
    }
    pub fn govern() {}
}
    
use crate::nation::government::govern;
use crate::nation::govern as nation_govern;

fn main() {
    nation_govern();
    govern();
}

rust也自带一些标准库,可以直接使用

rust标准库

错误处理

Rust中有一套独特的处理异常情况的机制,和C++中的try还是有很大区别的

Rust的错误有两种,可恢复错误和不可恢复错误

可恢复错误,例如说文件读写错误,这个文件有可能被其他程序占用,这是正常的,我们可以通过等待来解决这个问题

但是还有一种说逻辑错误导致的,例如数组越界访问,在C++中array是通过异常来表示的

Rust中则没有异常,对于这两种错误是有不同的处理方法的

不可恢复错误

这里我们需要使用宏,对于宏我们还是后面会具体讲,这里只是会用就行

我们来看一个宏函数panic!

rust 复制代码
fn main() {
    panic!("error occured");
    println!("Hello, Rust");
}

运行之后我们会发现,没有输出Hello, Rust, 而是在调用panic!之后就停止运行了

可恢复错误

在C/C++中,我们通常用整数做返回值来表达函数遇到的错误,但是Rust是通过一个枚举表达的

rust 复制代码
enum Result<T, E> {
    Ok(T),
    Err(E),
}

在标准库中,可能产生异常的函数的返回值都是Result枚举类型的

例如

rust 复制代码
use std::fs::File;

fn main() {
    let f = File::open("hello.txt");
    match f {
        Ok(file) => {
            println!("File opened successfully.");
        },
        Err(err) => {
            println!("Failed to open the file.");
        }
    }
}

如果用if let会更简单一些

rust 复制代码
use std::fs::File;

fn main() {
    let f = File::open("hello.txt");
    if let Ok(file) = f {
        println!("File opened successfully.");
    } else {
        println!("Failed to open the file.");
    }
}

如果想要一个可恢复错误按照不可恢复错误来处理,就可以使用两个方法

unwarp() expect(message: &str)

例如

rust 复制代码
use std::fs::File;

fn main() {
    let f1 = File::open("hello.txt").unwrap();
    let f2 = File::open("hello.txt").expect("Failed to open.");
}

这种就相当于在枚举是Err时调用panic!宏,区别就是expect可以发信息

错误传递

我们可以直接使用Err(value)作为枚举来传递错误,这里的value是泛型,可以传递任意类型的参数

泛型我们下一篇来详细讲

如果我们如果想要传递泛型,接收端想要再传递出去,那就得写一个match来判断

例如这样

rust 复制代码
fn g(i: i32) -> Result<i32, bool> {
    let t = f(i);
    return match t {
        Ok(i) => Ok(i),
        Err(b) => Err(b)
    };
}

然后Rust又给了一个语法糖,可以在返回值是Result枚举的情况下在函数末尾加一个?,就可以直接返回错误类型了

rust 复制代码
fn g(i: i32) -> Result<i32, bool> {
    let t = f(i)?;
    Ok(t)
}

这里要注意类型的统一

kind方法

Rust中好像没有类似try一样,可以把同一类型的错误全部放在一个相同的解决处理的能力

但是我们可以把处理异常单独写一个函数,然后使用异常里的kind方法,就能知道Result的Err类型了,然后就可以针对问题进行解决

例如

rust 复制代码
use std::io;
use std::io::Read;
use std::fs::File;

fn read_text_from_file(path: &str) -> Result<String, io::Error> {
    let mut f = File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

fn main() {
    let str_file = read_text_from_file("hello.txt");
    match str_file {
        Ok(s) => println!("{}", s),
        Err(e) => {
            match e.kind() {
                io::ErrorKind::NotFound => {
                    println!("No such file");
                },
                _ => {
                    println!("Cannot read the file");
                }
            }
        }
    }
}
相关推荐
无名之逆9 小时前
高性能文件上传服务
java·服务器·网络·http·rust
我爱拉臭臭10 小时前
趣味编程之go与rust的爱恨情仇
rust·go
叠叠乐10 小时前
Rust 中的Relaxed 内存指令重排演示:X=0 && Y=0 是怎么出现的?
开发语言·算法·rust
iwannay14 小时前
原神启动-用rust开发一款大型任务调度软件jiascheduler
rust
pumpkin8451415 小时前
学习笔记四——Rust 函数通俗入门
笔记·学习·rust
我是唐青枫16 小时前
Rust cargo 命令行工具使用教程
开发语言·后端·rust
Source.Liu16 小时前
【远程工具】0 std::process::Command 介绍
rust
pumpkin8451416 小时前
学习笔记九——Rust所有权机制
笔记·学习·rust
杜子源源1 天前
Rust-如何快速统计一个数字的位数
rust
憨憨2号1 天前
【14】RUST高级特性
开发语言·rust