rust高级特征
文章目录
- 不安全的rust
- 解引用裸指针
- 裸指针与引用和智能指针的区别
- 裸指针使用解引用运算符 *,这需要一个 unsafe 块
- 调用不安全函数或方法
- 在不安全的代码之上构建一个安全的抽象层
- 使用 extern 函数调用外部代码
- rust调用C语言函数
- rust接口被C语言程序调用
- 访问或修改可变静态变量
- 静态变量
- 可变静态变量
- 实现不安全 trait
- 访问联合体中的字段
- 高级trait
- 关联类型在 trait 定义中指定占位符类型
- 使用关联类型:针对一个类型的实现
- 使用泛型:针对多个类型的实现
- 参考
不安全的rust
不安全的rust提供的能力如下:
- 解引用裸指针
- 调用不安全的函数或方法
- 访问或修改可变静态变量
- 实现不安全 trait
- 访问 union 的字段
unsafe 并不会关闭借用检查器或禁用任何其他 Rust 安全检查:如果在不安全代码中使用引用,它仍会被检查。
unsafe 关键字只是提供了那五个不会被编译器检查内存安全的功能。你仍然能在不安全块中获得某种程度的安全。
解引用裸指针
裸指针与引用和智能指针的区别
- 允许忽略借用规则,可以同时拥有不可变和可变的指针,或多个指向相同位置的可变指针
- 不保证指向有效的内存
- 允许为空
- 不能实现任何自动清理功能
eg:如何从引用同时创建不可变和可变裸指针
#![allow(unused)]
fn main() {let mut num = 5;let r1 = &num as *const i32; //不可变裸指针let r2 = &mut num as *mut i32; //可变裸指针
}
裸指针使用解引用运算符 *,这需要一个 unsafe 块
#![allow(unused)]
fn main() {let mut num = 5;let r1 = &num as *const i32;let r2 = &mut num as *mut i32;unsafe {println!("r1 is: {}", *r1);println!("r2 is: {}", *r2);}
}
编译
▶ cargo runBlocking waiting for file lock on build directoryCompiling bobo v0.1.0 (/home/wangji/code/rust/bobo)Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.83sRunning `target/debug/bobo`
r1 is: 5
r2 is: 5
调用不安全函数或方法
#![allow(unused)]
fn main() {unsafe fn dangerous() {}// 必须在一个单独的 unsafe 块中调用 dangerous 函数unsafe {dangerous();}
}
在不安全的代码之上构建一个安全的抽象层
问题代码
#![allow(unused)]
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]);
}fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {let len = slice.len();assert!(mid <= len);// 不能对切片进行两次可变借用(&mut slice[..mid], &mut slice[mid..])
}
使用slice处理裸指针
#![allow(unused)]
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]);
}use std::slice;
// 切片slice包括指向某个数据的指针和数据的长度
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {let len = slice.len();let ptr = slice.as_mut_ptr(); // 返回指向slice中第一个元素的裸指针assert!(mid <= len);unsafe {(slice::from_raw_parts_mut(ptr, mid),slice::from_raw_parts_mut(ptr.add(mid), len - mid),)}
}
使用 extern 函数调用外部代码
extern,有助于创建和使用 外部函数接口(Foreign Function Interface, FFI)。外部函数接口是一个编程语言用以定义函数的方式,其允许不同(外部)编程语言调用这些函数。
如何集成 C 标准库中的 abs 函数。
rust调用C语言函数
extern "C" {fn abs(input: i32) -> i32;
}fn main() {unsafe {println!("Absolute value of -3 according to C: {}", abs(-3));}
}
rust接口被C语言程序调用
还需增加 #[no_mangle] 标注来告诉 Rust 编译器不要 mangle 此函数的名称。Mangling 发生于当编译器将我们指定的函数名修改为不同的名称时,这会增加用于其他编译过程的额外信息,不过会使其名称更难以阅读。
每一个编程语言的编译器都会以稍微不同的方式 mangle 函数名,所以为了使 Rust 函数能在其他语言中指定,必须禁用 Rust 编译器的 name mangling。
#![allow(unused)]
fn main() {#[no_mangle]pub extern "C" fn call_from_c() {println!("Just called a Rust function from C!");}
}
访问或修改可变静态变量
静态变量
rust中全局变量就是静态变量
static HELLO_WORLD: &str = "Hello, world!";fn main() {println!("name is: {}", HELLO_WORLD);
}
可变静态变量
访问不可变静态变量必须使用unsafe{}包起来
static mut COUNTER: u32 = 0;fn add_to_count(inc: u32) {unsafe {COUNTER += inc;}
}fn main() {add_to_count(3);unsafe {println!("COUNTER: {}", COUNTER);}
}
实现不安全 trait
#![allow(unused)]
fn main() {unsafe trait Foo {// methods go here}unsafe impl Foo for i32 {// method implementations go here}
}
访问联合体中的字段
高级trait
关联类型在 trait 定义中指定占位符类型
关联类型(associated types)是一个将类型占位符与 trait 相关联的方式,这样 trait 的方法签名中就可以使用这些占位符类型。trait 的实现者会针对特定的实现在这个类型的位置指定相应的具体类型。如此可以定义一个使用多种类型的 trait,直到实现此 trait 时都无需知道这些类型具体是什么。
使用关联类型:针对一个类型的实现
#![allow(unused)]
fn main() {}pub trait Iterator {//一个带有关联类型的 trait 的例子是标准库提供的 Iterator trait。它有一个叫做 Item 的关联类型来替代遍历的值的类型。type Item;fn next(&mut self) -> Option<Self::Item>;
}
struct Counter {}
impl Iterator for Counter {type Item = u32;fn next(&mut self) -> Option<Self::Item> {// --snip--Some(0)}
}// 报错!!
impl Iterator for Counter {type Item = u16;fn next(&mut self) -> Option<Self::Item> {// --snip--Some(0)}
}
使用泛型:针对多个类型的实现
使用泛型修改:可以支持多个类型
#![allow(unused)]
fn main() {}pub trait Iterator<T> {fn next(&mut self) -> Option<T>;
}
struct Counter {}
impl Iterator<u32> for Counter {fn next(&mut self) -> Option<u32> {// --snip--Some(0)}
}impl Iterator<u16> for Counter {fn next(&mut self) -> Option<u16> {// --snip--Some(0)}
}
参考
-
第19章~编写不安全的Rust代码
-
高级特征