前言
在上一章中, 初步认识了RUST, 这一章介绍下RUST的安全, 并在过程中带上基本类型等介绍.
注意, 此处的安全, 主要是指内存安全。
一、枚举
1.null处理
RUST是没有null的.
存在null的场景, 标准库方法一般返回的是, 枚举Option或者Result。
pub enum Option<T> {
/// No value.
None,
/// Some value of type `T`.
Some(T),
}
pub enum Result<T, E> {
/// Contains the success value
Ok(T),
/// Contains the error value
Err(E),
}
2.枚举使用示例
use std::fs;
fn main() {
// 读取名为"test"的文件,返回枚举Result. test文件中的内容是"hello world!"
let f = fs::read_to_string("test");
// 控制流支持if, 不过对于枚举, 一般使用match
match f {
// Ok(s), s代表了读取到的文件中的内容
Result::Ok(s)=>{
println!("f1:{}", s);
},
Result::Err(error)=>{
println!("{}", error);
}
}
// 读取文件"test2". 本示例中无该文件.
// 用unwrap来获得Result枚举中的数据,
// 读取失败则返回"没有该文件"
let f2 = fs::read_to_string("test2").unwrap_or("没有该文件".to_string());
println!("f2: {}", f2);
}
二、所有权
1.所有权是什么
所有权, 是RUST在内存管理上, 做出的最独特的设计
RUST没有垃圾回收GC, 用所有权来保障内存安全
所有权会在编译阶段进行判定:
编译器在编译时会根据一系列的规则进行检查。
如果违反了任何这些规则,程序都不能编译。
在运行时,所有权系统的任何功能都不会减慢程序。
2.所有权规则
1.Rust 中的每一个值都有一个被称为其所有者(owner)的变量。
2.值在任一时刻有且只有一个所有者。
3.当所有者(变量)离开作用域,这个值将被丢弃。
下面请看代码注释, 感受下所有权的奇妙之处.
let a = String::from(“abc”); // a获得所有权
let b = a; // a的所有权转移到了b
println!(“{}”, a);// 报错, 因为a已经失去了所有权, 即a走完了生命周期: value borrowed here after move
3.引用
直接赋值会导致所有权的转移, 使用多有不便. 因此, 可以用引用.
& 符号就是引用,它们允许你使用值但不获取其所有权
*符号来解引用, 获取值
对上面的代码略作修改, 第二行新增了"&", 则代码正常运行了
let a = String::from("abc"); // a获得所有权
let b = &a; // b拿到a的引用,所有权并未转移
println!("{}", a);// 未报错
println!("{}", *b);// *来解引用
4.可变引用
RUST的变量, 默认是不可变的, 其引用也是默认不可变的.
用mut表示可变
在第一行和第二行, 都新增了"mut"关键字
let mut a = String::from("abc"); // a获得所有权,mut可变,表示允许修改值
let b = &mut a; // b拿到a的可变引用,所有权并未转移
b.push_str("defg"); // 修改了a的值
println!("{}", a);// 未报错,打印出"abcdefg"
5.引用的规则
- 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用。
- 引用必须总是有效的。
第1点很好理解, 引用如果可变, 那么等于说是可以直接修改值了, 为了内存安全自然要限制.
第2点, 引出一个重要概念: 悬垂引用
悬垂引用, 是指该引用指向的内存可能已经被分配给其它持有者
fn main() {
let s = getString();
}
fn getString() -> &String{
let a = String::from(“abc”);
&a // 返回a的引用. 不加“;”时, 等同于“return &a;”
// a的生命周期已经结束了, 因此&a这个引用也无效了, 这样的引用称之为”悬垂引用”
}
6.字符串slice引用
&str类型是字符串的slice引用, slice意思是切片, 也就是指只引用了字符串中的一部分值.
由于是引用, 所以没有所有权
注意, let b = “abcdefg” 这种写法, 返回的是&str, 而不是String
// a是String类型, 拥有值的所有权.
// 存放在堆上, 长度可变
let a = String::from(“abcdefg”);
// b是&str类型, 是个slice引用, 没有值的所有权.
// 存放在栈上, 长度在编译时就固定了, 指向了堆上的值
let b = “abcdefg”;
// c的值是ab. c是&str类型, 是个slice引用, 没有值的所有权.
// 存放在栈上, 长度在编译时就固定了, 指向了堆上的值
let c = &a[0..2];
// &str和&String的主要区别:
// &str可以指向字符串的部分内容,
// &String指向的是完整的字符串
7.Copy trait
上面这段报错的代码, 把a从String类型, 改为整数, 发现不报错了
let a = 123; // a获得所有权
let b = a; // a的所有权转移到了b吗?
println!(“{}”, a);// 未报错, 说明a的所有权没有转移, 为何没报错?
原因就是Copy trait
整数型不报错, 是因为它实现了Copy特性,
let b = a; 把a的值做了个克隆, 产生了新的值, 赋予了b,因此a的所有权没有转移给b
常见的实现了Copy 的类型:
- 所有整数类型,比如 u32。u表示unsigned无符号, i32就是32位有正负符号的
- 布尔类型,bool,它的值是 true 和 false。
- 所有浮点数类型,比如 f64。f64就是64位的float类型, 用指数来表示, 会有精度丢失
- 字符类型,char。
- 元组,当且仅当其包含的类型也都实现 Copy 的时候。比如,(i32, i32) 实现了 Copy,但 (i32, String) 就没有。
总结
本章介绍了RUST的安全, 后面介绍下面向对象和函数式编程, 帮助理解
下一章: RUST的面向对象和函数式编程