Rust 学习笔记

前置工作

  1. 安装
curl https://sh.rustup.rs -sSf | sh

添加到 PATH

export PATH="$HOME/.cargo/bin:$PATH"
  1. 更新
rustup update
  1. 文档
rustup doc
  1. 非官方库文档
cargo doc -p <package> --open

cargo 使用crate:
Cargo.toml 下:

[dependicies] 
rand ="0.5.0"

版本号使用语义化版本号
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

1. 主版本号:当你做了不兼容的 API 修改,
2. 次版本号:当你做了向下兼容的功能性新增,
3. 修订号:当你做了向下兼容的问题修正。

先行版本号及版本编译元数据可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

基本内容

数据类型:char是unicode编码的,占 4 个字节。
复合类型:
元组:(1,2.1,'3') 也可以解构,还可以使用 '.' 访问。
数组:

let a: [i32;5] = [1,2,3,4,5];

if:

let number = 3;
if number < 5 {
    println!("something");
}

let 语句中使用 if。
循环:
loop:

let result = loop {
    break 2; // 使用break 返回值
}

所有权:
变量和数据的交互方式:移动,克隆
模块系统:
package:可以包含多个crate
crate:可以包含一个lib或多个可执行文件
module 和 use
可以在 src/bin 目录下添加源文件来生成更多的可执行包。
所有默认私有,父级的模块不能直接使用,但是子级的可以。
使用 as 来重命名。
动态数组:Vec
HashMap:
在键不存在时插入值:

score.entry(String::from("Blue")).or_insert(50);

错误处理:
panic 的栈展开:
错误发生时,默认会进行栈展开,进行清理工作,会使二进制程序体积变大。也可以不进行栈展开,直接退出,留给操作系统清理。
可以在 Cargo.toml 中的 [profile] 选项中设置 panic='abort' 来直接终止。

[profile]
panic = 'abort'

对 Result<T,E> 的处理:
unwrapexpect:
unwrap 可以在 Ok(T) 时直接返回,Err(E) 时panic!.
expectunwrap 类似,但是可以在panic时输出自定义错误信息。
错误传递:
?标志符可以自动调用from函数,把错误类型转换成当前函数的返回类型,且只能用于返回Result的函数。
Box trait对象,“任何可能的错误类型”
错误的处理原则:在代码处于损坏状态时 panic。
利用自定义类型来进行有效性验证。
提高程序的代码复用:

  1. 识别重复代码与提取成函数
  2. 识别只有参数类型不同的函数提取成泛型

泛型: 函数,结构体,枚举,方法(impl)
trait:定义共享行为,类似接口
trait 定义:

pub trait Traitname {
    fn somefun(&self) -> String;
}

为类型实现trait:

impl Traitname for Structname {}

限制:只用当 trait或类型定义于我们的库时,我们才可以为该类型实现对应的trait,不能为外部类型实现外部trait,孤儿规则,保证代码一致性,别人的代码不会破坏我们的代码。
默认实现:
可以在默认实现中调用还为实现的其他方法.无法在重载方法时调用其默认实现
trait 作为参数:

pub fn notify(item: impl Summary) {}

trait 约束:

pub fn notify<T: Summary>(item: T) {}

使用 + 语法指定多个trait约束:

pub fn notify(item: impl Summary + Display) {}
pub fn notify<T: Summary + Display>(item: T) {}

使用where语句简化trait约束:

fn some_funtion<T,U>(t: T,u: U) -> i32
where T: Display + Clone,
    U: Clone + Debug
    {}

返回实现了trait的类型:

fn return_summary() -> impl Summary {}

但是只能返回一个类型,不能返回 Tweet 或 NewsArticle,可以使用trait对象.
利用trait 约束来有条件的实现方法:

impl<T: Display + PartialOrd> Pair<T> {
    fn cmd_display() {}
}

使用生命周期保证引用的有效性
使用生命周期来避免悬垂引用

fn longest<'a>(x: &'a str,y: &'a str) -> &'a str { }

结构体中的生命周期标注

struct ImportantExcerpt<'a> {
    part: &'a str,
}

生命周期省略

  1. 每个引用参数会有自己的生命周期参数。
  2. 只有一个输入生命周期参数时,会被赋给所有输出生命周期参数。
  3. 当有多个输入生命周期参数,其中一个是&self 或&mut self时,self 的生命周期会被赋给所有输出生命周期参数。

方法定义中的生命周期标注

impl<'a> ImportantExpert<'a> {
    fn level(&self) -> i32 {
        3
    }
}

impl和类型名称后面的生命周期是不能省略的。
静态生命周期'static,代表整个程序的执行期,字符串字面量就是一种。
自动化测试

  1. 准备需要的数据和状态
  2. 调用需要测试的代码
  3. 断言运行结果和我们所期望的一致

#[test] 是一个属性,加到关键字 fn 上一行就可以把函数变成测试函数。

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2+2,4);
    }
}

添加自定义的错误提示信息:

assert!(result.contains("Carol"),"Greeting did not contain name,value is {}",result);

使用 should_panic 检查 panic
为可能pacnic的测试函数添加 should_panic 属性。

#[test]
#[should_panic]

给should_panic添加expected信息,检查panic的错误信息。

#[test]
#[should_panic(expected="Guess value...")]

使用 Result<T,E> 编写测试
让测试函数返回Result,测试成功返回Ok(()),失败返回Err("error message")

cargo test -- <参数> # 可以测试程序的命令行参数

默认多线程测试,如果需要单线程

cargo test -- --test-threads=1

显示函数输出

cargo test -- --show-output

通过名字过滤运行测试

cargo test one

默认忽略测试

#[test]
#[ignore]

只运行忽略测试

cargo test -- --ignored

测试组织
单元测试
#[cfg(test)] 用于定义测试模块
可以直接测试私有函数
集成测试
在根目录下的tests 子目录
指定运行某个测试

cargo test --test test_name

未完待续

原文地址:https://www.cnblogs.com/ttxs69/p/14532713.html