前置工作
- 安装
curl https://sh.rustup.rs -sSf | sh
添加到 PATH
:
export PATH="$HOME/.cargo/bin:$PATH"
- 更新
rustup update
- 文档
rustup doc
- 非官方库文档
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> 的处理:
unwrap
和 expect
:
unwrap
可以在 Ok(T)
时直接返回,Err(E)
时panic!.
expect
和 unwrap
类似,但是可以在panic时输出自定义错误信息。
错误传递:
?标志符可以自动调用from函数,把错误类型转换成当前函数的返回类型,且只能用于返回Result的函数。
Box
错误的处理原则:在代码处于损坏状态时 panic。
利用自定义类型来进行有效性验证。
提高程序的代码复用:
- 识别重复代码与提取成函数
- 识别只有参数类型不同的函数提取成泛型
泛型: 函数,结构体,枚举,方法(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,
}
生命周期省略
- 每个引用参数会有自己的生命周期参数。
- 只有一个输入生命周期参数时,会被赋给所有输出生命周期参数。
- 当有多个输入生命周期参数,其中一个是&self 或&mut self时,self 的生命周期会被赋给所有输出生命周期参数。
方法定义中的生命周期标注
impl<'a> ImportantExpert<'a> {
fn level(&self) -> i32 {
3
}
}
impl和类型名称后面的生命周期是不能省略的。
静态生命周期'static,代表整个程序的执行期,字符串字面量就是一种。
自动化测试
- 准备需要的数据和状态
- 调用需要测试的代码
- 断言运行结果和我们所期望的一致
#[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