跟着谷歌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 排版

相关推荐
会说法语的猪1 小时前
springboot实现图片上传、下载功能
java·spring boot·后端
用户4694651597831 小时前
Rust使用tracing记录日志
rust
凡人的AI工具箱1 小时前
每天40分玩转Django:实操多语言博客
人工智能·后端·python·django·sqlite
Cachel wood1 小时前
Django REST framework (DRF)中的api_view和APIView权限控制
javascript·vue.js·后端·python·ui·django·前端框架
m0_748234081 小时前
Spring Boot教程之三十一:入门 Web
前端·spring boot·后端
想成为高手4991 小时前
国产之光--仓颉编程语言的实战案例分析
后端
编码浪子2 小时前
构建一个rust生产应用读书笔记7-确认邮件2
开发语言·后端·rust
昙鱼2 小时前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
白宇横流学长2 小时前
基于SpringBoot的停车场管理系统设计与实现【源码+文档+部署讲解】
java·spring boot·后端
kirito学长-Java3 小时前
springboot/ssm太原学院商铺管理系统Java代码编写web在线购物商城
java·spring boot·后端