跟着谷歌Android团队学习Rust,Rust如何保证程序运行安全?

大家好,我是梦兽编程。没错Rust系列将以谷歌安卓团队分享的Rust经验进行持续更新。

这是由 Google 的 Android 团队开发的免费 Rust 课程。本课程涵盖了 Rust 的方方面面,从基本语法到泛型和错误处理等高级主题。

该课程的最新版本可以在 google.github.io/comprehensi...

Rust是如何保证安全的?

相信大家听闻Rust都是以它的安全性宣传,那问题来了Rust是如何保证的安全性?Rust的编译器在给我们做了以下的操作。

Rust编译器做了很多限制,在编译时对静态内存做了一下处理:

没有未初始化的变量

Rust 的所有变量都必须在使用前进行初始化。这意味着在使用变量之前,必须将其分配一个值。Rust 编译器会在编译时检查所有变量是否已被初始化,如果未初始化,则会报错。比如以下情况:

rust 复制代码
fn main() {
 let x:i32;
 println!("x -> {}",x)
}

Java和Golang这一类的语言初始变量时候已经默认给我们带上了默认值。如果不给默认值的话估计你会遇到类似(javascript)这种undefined的情况,可能导致你的系统出现问题。

没有内存泄漏

Rust 使用所有权系统来管理内存。所有权系统将所有内存分配与其所有者联系起来。当所有者离开作用域时,其所拥有的内存将被自动释放。

初学者会对Rust的内存权限很难掌握,但没特别是借用引用这些关系应用在生命周期当中。

这意味着在大多数情况下,Rust 程序不会发生内存泄漏。但是,在以下情况下,Rust 程序可能会发生内存泄漏:

  • 使用 Rc 或 Weak 智能指针。
  • 使用 Box 智能指针。
  • 使用 unsafe 代码。 通常在引用一些C代码块的时候需要用上unsafe来绕过编译器的检查

没有双重释放

Rust 编译器会在编译时检查所有内存是否已被释放两次。如果一个内存块已被释放两次,则会报错。

csharp 复制代码
fn main(){
	let mut ptr = Box::new(5);
	// 释放内存
    ptr.drop();
    // 再次释放内存 Error
    ptr.drop();
}

释放后不使用

Rust 编译器会在编译时检查所有已释放的内存是否仍然被使用。如果一个已释放的内存块仍然被使用,则会报错。

rust 复制代码
fn main() {
    let mut ptr = Box::new(5);

    // 释放内存
    ptr.drop();

    // 尝试使用已释放的内存
    // 这将导致错误
    println!("{}", *ptr);
}

没有NULL指向

Rust 的所有指针都必须指向有效的内存。如果一个指针指向无效的内存,则会导致程序崩溃。Rust 编译器会在编译时检查所有指针是否指向有效的内存,如果一个指针指向无效的内存,则会报错。

rust 复制代码
fn main() {
    let ptr: *mut i32 = null;

    // 尝试使用 `ptr`
    // 这将导致错误
    println!("{}", *ptr);
}

没有忘记锁的释放

在并发开发中,线程和线程之间我们往往需要使用锁来保证线程与线程之间的资源争夺,使用锁。往往锁使用不好就很容易形成死锁,特别有些新手在java语言或者golang这一类语法中,使用完锁却忘记释放,导致下一次的访问,其他线程都在等待锁的释放进行下一轮的资源争夺。

在Rust中是拒绝这种情况发生的。

csharp 复制代码
fn main() {
    let mut mtx = Mutex::new(0);

    // 尝试获取互斥锁
    // 这将成功
    let mut guard = mtx.lock();

    // 做一些事情

    // 忘记解锁互斥锁
}

正确的做法。

csharp 复制代码
fn main() {
    let mut mtx = Mutex::new(0);

    // 尝试获取互斥锁
    // 这将成功
    let mut guard = mtx.lock();

    // 做一些事情

    // 正确解锁互斥锁
    guard.unlock();
}

没有迭代器的实效

如果你有时候需要手写一个迭代器的时候,在java或golang这些运行时的语言中,可能会出现以下写法问题,梦兽编程这里以Java举例子,因为golang没有自带迭代器,golang团队推荐使用for。

vbnet 复制代码
public class IteratorTest {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        Iterator<Integer> iter = list.iterator();

        // 迭代器的范围结束
        iter.next();
        iter.next();
        iter.next();

        // 尝试使用已超出范围的迭代器
        // 这将导致程序崩溃
        System.out.println(iter.next());
    }
}

这里的代码JAVA代码是可以编译成功的,只有运行时才会保存,直接导致你的程序崩溃,不得不去重启服务。

以上的问题在Rust中编译器是服务让你编译成功的。

scss 复制代码
fn main() {
    let mut iter = vec![1, 2, 3].into_iter();

    // 迭代器的范围结束
    iter.next();
    iter.next();
    iter.next();

    // 尝试使用已超出范围的迭代器
    // 这将导致错误
    println!("{}", iter.next().unwrap());
}

output Info: 编译很贴心的告诉你,你超出访问了不应该写三个next() ^_^

python 复制代码
error[E0502]: cannot borrow `iter` as mutable, as it is not declared as mutable
  --> src/main.rs:10:5
   |
9 |     iter.next();
   |     iter.next();
   |     iter.next();
   |     ^ value used here after move

好了以上就是本次的所有内容,希望能为你解答出Rust是如何保证程序的运行安全有所理解,这里是梦兽编程-本次系列是根本《谷歌安卓团队学习Rust》。

rexweb.link/category/te...]

  1. 梦兽编程倔强号
  2. 梦兽编程知乎
  3. 梦兽编程bilibili

微信搜索梦兽编程公众号

##梦兽编程倔强号 juejin.cn/user/206673...

##梦兽编程知乎 www.zhihu.com/people/mo-d...

##梦兽编程bilibili space.bilibili.com/106325238?s...

参考资料

1

google.github.io/comprehensi...: google.github.io/comprehensi...

2

跟着谷歌团队学Rust: rexweb.link/category/te...

3

梦兽编程: rexweb.link

本文使用 markdown.com.cn 排版

相关推荐
uzong2 小时前
技术故障复盘模版
后端
GetcharZp2 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程2 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研2 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi3 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国4 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy4 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack4 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt
bobz9655 小时前
pip install 已经不再安全
后端
寻月隐君5 小时前
硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端
后端·rust·github