0
点赞
收藏
分享

微信扫一扫

研读Rust圣经解析——Rust learn-15(unsafe Rust )

静守幸福 2023-04-30 阅读 90

研读Rust圣经解析——Rust learn-15(unsafe Rust )

不安全的Rust

Rust 还隐藏有第二种语言,它不会强制执行这类内存安全保证:这被称为 不安全 Rust(unsafe Rust)

主要来说共有5大操作

  1. 解引用裸指针
  2. 调用不安全的函数或方法
  3. 访问或修改可变静态变量
  4. 实现不安全 trait
  5. 访问 union 的字段

不过在这里我们只看1,2,3

unsafe关键字

使用unsafe 关键字我们可以创建一块不安全的区域,在其中使用unsafe rust

unsafe{
	//...
}

解引用裸指针

裸指针是可变或不可变的
应用于调用c语言中的接口
裸指针与引用和智能指针的区别在于:

  1. 允许忽略借用规则,可以同时拥有不可变和可变的指针,或多个指向相同位置的可变指针
  2. 不保证指向有效的内存
  3. 允许为空
  4. 不能实现任何自动清理功能

声明一个不可变的裸指针

不可变使用关键字*const并在后部指明类型

let a = 1;
let b = &a as *const i32;

声明可变的裸指针

可变使用关键字*mut并在后部指明类型

let c = &a as *mut i32;

注意点

可以在安全代码中 创建裸指针,只是不能在不安全块之外 解引用裸指针

调用不安全函数或方法

我们通过unsafe关键字可以设置一块区域,区域中使用不安全的代码(函数)

//声明
unsafe fn func(){}
//调用
unsafe{
	func();
}

创建不安全代码的安全抽象

仅仅因为函数包含不安全代码并不意味着整个函数都需要标记为不安全的。事实上,将不安全代码封装进安全函数是一个常见的抽象

以下是官方的例子:

fn main() {
    let mut v = vec![1, 2, 3, 4, 5, 6];

    let r = &mut v[..];

    let (a, b) = r.split_at_mut(3);

    assert_eq!(a, &mut [1, 2, 3]);
    assert_eq!(b, &mut [4, 5, 6]);
}

由于官方对split_at_mut说的非常详细,我再去复制显然没什么必要https://kaisery.github.io/trpl-zh-cn/ch19-01-unsafe-rust.html添加链接描述

使用 extern 函数调用外部代码

我们在学习一些Rust项目的时候,我们很可能在代码中看到一些使用其他语言的例子,事实上这个特性并不是Rust所独有的,只是你在Rust中使用起来更加为所欲为,在其他语言中,很可能是语言帮你隐式的调用,而非你能够感受的到(如:Java获取环境变量)
extern关键字可以创建一个外部函数接口以使用其他语言的函数,以下是调用了C语言中的abs函数,至于成不成功,这需要程序员保证,而不是Rust

extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    unsafe {
        println!("Absolute value of -3 according to C: {}", abs(-3));
    }
}

使用 extern#[no_mangle] 暴露Rust函数给其他语言

相应的,可以调用别的语言的函数,我们也可以暴露自己的函数让其他语言调用

Rust中有一个宏:#[no_mangle]

#[no_mangle]
pub extern "Java" fn get_env(){
	return env::args().collect();
}

访问或修改可变静态变量

数据竞争:当多个线程访问相同的可变全局变量,通常静态变量的名称采用SCREAMING_SNAKE_CASE写法。静态变量只能储存拥有 'static 生命周期的引用,这意味着 Rust 编译器可以自己计算出其生命周期而无需显式标注。访问不可变静态变量是安全的。

声明静态变量

使用static关键字对静态变量进行声明

static TEST: &str = "TEST";

修改静态变量

由于修改静态变量是非安全的操作,所以我们必须要在unsafe块中

static mut TEST: i32 = 100;

fn add() {
    unsafe {
        TEST += 5
    }
}

fn main() {
    add();
    unsafe {
        println!("{}", TEST);
    }
}

而当多个线程进行访问的时候我们需要用到消息传递机制和共享状态保证数据竞争不会发生

举报

相关推荐

0 条评论