搭建企业网站,优秀网页版式设计,在线做网站免费黄搞,域名购买 网站建设Rust 是 静态类型#xff08;statically typed#xff09; 语言#xff0c; 也就是说在编译时就必须知道所有变量的类型#xff0c; 这一点将贯穿整个章节。
C/C的安全问题 内存的不正确访问引发的内存安全问题 由于多个变量指向同一块内存区域导致的数据一致性问题 由于… Rust 是 静态类型statically typed 语言 也就是说在编译时就必须知道所有变量的类型 这一点将贯穿整个章节。
C/C的安全问题 内存的不正确访问引发的内存安全问题 由于多个变量指向同一块内存区域导致的数据一致性问题 由于变量在多个线程中传递导致的数据竞争的问题由第一个问题引发的内存安全问题一般有 5 个典型情况
使用未初始化的内存对空指针解引用悬垂指针(使用已经被释放的内存)缓冲区溢出非法释放内存(释放未分配的指针或重复释放指针)
Rust 解决以上问题的方法
编号问题方案1使用未初始化的内存编译器禁止变量读取未赋值变量2对空指针解引用使用 Option 枚举替代空指针3悬垂指针生命周期标识与编译器检查4缓冲区溢出编译器检查拒绝超越缓冲区边界的数据访问5非法释放内存语言级的 RAII 机制只有唯一的所有者才有权释放内存(引用不能释放借用的变量内存)6多个变量修改同一块内存区域允多个变量借用所有权但是同一时间只允许一个可变借用7变量在多个线程中传递时的安全问题对基本数据类型用 Sync 和 Send 两个 Trait 标识其线程安全特性即能否转移所有权或传递可变借用把这作为基本事实。再利用泛型限定语法和 Trait impl 语法描述出类型线程安全的规则。编译期间使用类似规则引擎的机制基于基本事实和预定义规则为用户代码中的跨线程数据传递做推理检查
安全措施
所有权转移 避免大块内存的拷贝直接通过所有权转移即可避免全量数据的拷贝提高效率。
变量的不可变性 一旦绑定就不能修改需要显示的重新绑定新的变量。
let a 8;类型的显示转换 在操作的过程中不能进行隐式转换避免编程时隐式转换到导致的问题
// u32 和 f64 相加会编译报错
let sum 3 3.1;// 使用 u8 类型做简单判断是编译报错
let number: u8 3;
if number { // 可以改为 if number ! 0println!(number was three);
}严格的数值溢出检查 计算时提供严格的数值溢出检查会直接在编译时就会报错而不是在执行的过程中发现问题。
// 编译时直接报错
let a_u8: u8 254;
let b a_u8 20;严格的静态数组越界检查 在编译时会检查数组是否越界如果越界则会直接报错。
let arry [1, 2, 3];
println!(a1: {}, a2: {}, a3: {}, arry[0], arry[1], arry[2]);
// 编译时直接报错
println!(a3: {}, arry[3]);结构体全员初始化 结构体初始化时必须要初始化所有成员防止出现未初始化使用问题。 struct User { // 定义结构体类型注意类型之后不带 ;age: u8,height: f32,name: String,email: String,}let user4 User {// 结构体初始化每个字段都需要进行初始化age: 18,height: 180.3,name: String::from(Tom),email:String::from(Tomqq.com),};字符串内存的自动释放 可变字符串在创建时是申请堆内存进行创建的在离开作用域时会自动调用drop() 函数进行内存释放从而实现自动的内存释放.
{let s String::from(你好A);for i in s.chars() { // 以Unicode 编码遍历字符串println!({}, i);}println!();
}// s 绑定的字符串在离开作用域时会自动调用drop() 函数进行内存释放支持 Option 类型 支持Option可以有效的检查到 None 情况例如动态数组中数组越界问题通过语法的强制性解决潜在问题。
let v vec![1, 2, 3, 4, 5];// 执行时会出现问题
let does_not_exist v[100];
// 执行是
let does_not_exist v.get(100);
match v.get(does_not_exist) {Some(x) // TODO:,None // 为None 情况TODO
}同一作用域内引用的强制管理 不允许同一作用域中在使用可变引用后再使用不可变引用防止出现可变引用修改了内存再次使用不可变引用时导致问题。
let mut v vec![1, 2, 3, 4, 5];
let first v[0]; // 不可变引用
v.push(6); // 可变引用
println!(The first element is: {} first);// 在同一作用域内在使用可变引用后不允许再使用不可变引用可变借用只能一次 同一个变量的可变借用只能有一个防止多个引用修改变量导致出现一致性问题。
let mut v 10;
let x v; // 不可变引用可以存在多个
let mut a v; // 可变引用
// let mut b v; // 出现错误变量可变引用只能的存在一个
*a 12生命周期 生命周期的存在解决C/C中函数可能返回局部指针导致野指针的问题。
struct V{v:i32
}
fn bad_fn() - V{ //编译错误期望一个命名的生命周期参数因为返回了一个悬垂指针let a V{v:10};a
} let res bad_fn();const fn 编译时计算 const fn 支持在编译时将函数的结果结算出来提高编译效率。 const fn add(a: usize, b: usize) - usize {a b}const RESULT: usize add(5, 10); // 在编译时就已经计算出值为15而不需在运行时计算println!(The result is: {}, RESULT);路西法 的个人博客拥有更多美文等你来读。