RUST入门(二)


前言

上一章中, 初步认识了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. 引用必须总是有效的。

第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 的类型:

  1. 所有整数类型,比如 u32。u表示unsigned无符号, i32就是32位有正负符号的
  2. 布尔类型,bool,它的值是 true 和 false。
  3. 所有浮点数类型,比如 f64。f64就是64位的float类型, 用指数来表示, 会有精度丢失
  4. 字符类型,char。
  5. 元组,当且仅当其包含的类型也都实现 Copy 的时候。比如,(i32, i32) 实现了 Copy,但 (i32, String) 就没有。

总结

本章介绍了RUST的安全, 后面介绍下面向对象和函数式编程, 帮助理解
下一章: RUST的面向对象和函数式编程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值