Rust 学习(4)

十九. rust 高级特性

19.1 不安全rust

目前为止讨论过的代码都有 Rust 在编译时会强制执行的内存安全保证。然而,Rust 还隐藏有第二种语言,它不会强制执行这类内存安全保证:这被称为 不安全 Rustunsafe Rust)。它与常规 Rust 代码无异,但是会提供额外的超能力。

所谓的不安全是指,编译器无法确保足够的安全;

如果使用不安全的rust

unsafe:  unsafe 关键字只是提供了那五个不会被编译器检查内存安全的功能,因此保持unsafe 代码快的足够小非常与必要;

不安全包含那些方面;

  • 解引用裸指针 | Dereference raw pointers
  • 调用不安全的函数或方法 |  Call unsafe functions 
  • 访问或修改可变静态变量 |Mutate statics (including external ones)
  • 实现不安全 trait |Implement unsafe traits
  • 访问 union 的字段 | Access fields of unions

解决不安全的方式:将不安全代码封装进一个安全的抽象并提供安全 API

19.1.1 解引用裹指针

裸指针是不可变或可变的,分别写作 *const T 和 *mut T

裸指针与引用和智能指针的区别在于:

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

//可以在安全代码中 创建 裸指针,只是不能在不安全块之外 解引用 裸指针
    let mut num = 5;
    let r1 = &num as *const i32;//这里使用 as 将不可变和可变引用强转为对应的裸指针类型
    let r2 = &mut num as *mut i32;//这里使用 as 将不可变和可变引用强转为对应的裸指针类型

 //unsafe 代码
fn main() {
    println!("{:p}", &5);
    //可以在安全代码中 创建 裸指针,只是不能在不安全块之外 解引用 裸指针
    let mut num = 5;
    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;


    unsafe {//解引用裹指针
        println!("r1 = {:?}", *r1);
        println!("r2 = {:?}", *r2);
    }
    // let address = 0x012345usize;
    // let r = address as *const i32;
    // print!("{:p}",r);
}
19.1.2 Call unsafe functions 

fn main() {
    unsafe {//调用不安全的方法
        dangerous();
    }
}
unsafe fn dangerous() {}
19.1.3 使用extend 调用外部代码
//unsafe 代码
extern "C" {
    fn abs(input: i32) -> i32;
}
fn main() {
    unsafe {
        // 调用外部函数
        println!("{}", abs(-10));//10
    }
}

19.1.4 Mutate statics (including external ones)

static HELLO_WORLD: &str = "Hello, world!";
static mut COUNT: u32 = 0; //不变静态变量
fn add_to_count(inc: u32) {
    unsafe {
        //修改可变静态变量
        COUNT += inc;
    }
}
fn main() {
    println!("{}", HELLO_WORLD);

    add_to_count(100); //调用函数
    unsafe {
        println!("COUNT: {}", COUNT); /*访问可变静态变量*/ // COUNT: 100
    }
}
19.1.5 Implement unsafe traits

unsafe trait Foo { // methods go here }

unsafe impl Foo for i32 { // method implementations go here }

19.1.6 Access fields of unions
#[repr(C)]
union Myunion {
    f1: u32,
    f2: f32,
}
fn main() {
    let u = Myunion { f1: 100 };
    //访问联合体字段
    let f = unsafe { u.f1 };
    print!("{}", f);//100
}

19.2 高级trait (后续继续研究)

关联类型associated types)是一个将类型占位符与 trait 相关联的方式,这样 trait 的方法签名中就可以使用这些占位符类型

type :占位符类型(类型占位符);

当使用泛型类型参数时,可以为泛型指定一个默认的具体类型。如果默认类型就足够的话,这消除了为具体类型实现 trait 的需要。为泛型类型指定默认类型的语法是在声明泛型类型时使用 <PlaceholderType=ConcreteType>。】

这种情况的一个非常好的例子是用于运算符重载。运算符重载Operator overloading)是指在特定情况下自定义运算符(比如 +)行为的操作。

use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Mystruct {
    x: u32,
    y: u32,
}

impl Add for Mystruct {
    type Output = Mystruct;
    fn add(self, other: Mystruct) -> Mystruct {
        Mystruct {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

fn main() {
    assert_eq!(
        Mystruct { x: 1, y: 2 }.add(Mystruct { x: 3, y: 4 }),
        Mystruct { x: 4, y: 6 }
    );
}

19.3 高级类型

Rust 还提供了声明 类型别名type alias)的能力


fn main(){
    type kind = u32;
    let x = 5;
    let y: kind = 10;
    println!("x is {}, y is {}", x, y);
}

因为 Rust 需要知道例如应该为特定类型的值分配多少空间这样的信息其类型系统的一个特定的角落可能令人迷惑:这就是 动态大小类型dynamically sized types)的概念。这有时被称为 “DST” 或 “unsized types”,这些类型允许我们处理只有在运行时才知道大小的类型。

fn generic<T: Sized>(t: T) {
    // --snip--
}
fn generic<T: ?Sized>(t: &T) {
    // --snip--
}
?Sized trait bound 与 Sized 相对;也就是说,它可以读作 “T 可能是也可能不是 Sized 的”。这个语法只能用于 Sized ,而不能用于其他 trait;

总结:函数指针,闭包和宏 明天在继续;高级特性学习起来真有意思,真难理解,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值