• Rust 智能指针(一)


    Rust 智能指针(一)

    1.Box<T>

    Box<T>是指向堆中的指针。

    fn main() {
        let box = Box::new(3);
        println!("{}", box);
    }
    

    在出了指针的作用域之后,指针和它指向的对象都将被释放。

    在本例中,box将在main函数之后被释放。

    由于Box<T>的大小是确定的(size类型的大小),所以可以使用Box编写嵌套类型,比如实现链表。

    2.Deref trait

    实现Deref这个trait可以重载解引用运算符(*),这样可以把Deref trait当作普通引用。

    use std::ops::Deref;
    
    fn main() {
        let b=MyBox::new(12);
        assert_eq!(*b,12);
    }
    
    struct MyBox<T>(T);
    
    impl<T> MyBox<T> {
        fn new(value: T) -> Self {
            MyBox(value)
        }
    }
    
    impl<T> Deref for MyBox<T> {
        type Target = T;
    
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    
    

    当调用*b时,本质上是*(b.deref()),这样&引用和Deref引用的形式就统一了。

    函数和方法的隐式解引用强制多态

    假设我们有一个函数,它需要一个&str类型的参数。

    fn print_name(name: &str){
        println!("name:{}",name);
    }
    

    改变main中的代码

    let string = MyBox::new(String::from("My Box"));
    print_name(&(*string))
    

    *string获得 String 类型,调用String类型的&来获取&str类型(可以查看标准库,实现了AsRef<str> trait)。

    如果没有隐式解引用强制多态,我们需要这么写代码。很明显,这种写法太啰嗦了,本来rust的符号一大堆,现在这样子根本无法忍受。

    我们稍微更改一下

    print_name(&string);
    

    其他代码不变,把参数改为&string,明显,这是获取一个&MyBox<String>的对象,然后rust会自动调用deref()转为&String&String调用deref()转为&str(String也实现了Deref trait),这样子就与函数签名匹配了,编译通过。

    也就是,rust会隐式解引用来匹配所声明变量(参数)的类型。

    let a:&str = &string;
    println!("{}", a);
    

    这样的代码也是有效的。

    Rust 在发现类型和 trait 实现满足三种情况时会进行解引用强制多态:

    • T: Deref<Target=U> 时从 &T&U
    • T: DerefMut<Target=U> 时从 &mut T&mut U
    • T: Deref<Target=U> 时从 &mut T&U

    Deref trait 解引用为 &T ,即不可变引用, 而 DerefMut trait 解引用为 &mut T,是可变引用。

    3.Drop trait

    Drop是专门用来进行一些资源释放的操作,比如IO操作,当对象离开作用域时,会自动调用 Dropdrop 方法来释放资源。

    use std::fmt::Display;
    
    fn main() {
        let mb=MyBox::new(2);
        println!("the end");
    }
    
    struct MyBox<T:Display>(T);
    
    impl<T:Display> MyBox<T> {
        fn new(value: T) -> Self {
            MyBox(value)
        }
    }
    impl<T:Display> Drop for MyBox<T>{
        fn drop(&mut self) {
            println!("the data is {}",self.0);
        }
    }
    

    泛型约束T:Display是为了让它能够被打印。这段代码最终输出

    the end
    the data is 2
    

    提前释放资源

    有时候,我们需要提前释放资源。比如写入文件完成后,需要立马 close 。但是,Drop::drop 是不允许手动调用的,这时,我们需要 std::mem::drop 函数来释放。

    修改main函数

    fn main() {
        let mb=MyBox::new(2);
        drop(mb);
        println!("the end");
    }
    

    输出结果

    the data is 2
    the end
    

    这表明,Drop::drop被提前调用了,并且只调用了一次。

    注意 std::mem::drop 的参数是 move 语义,也就是说,在调用 std::mem::drop 之后,mb 已经被移动,不能够再用了。

    那么这个函数是怎么实现的呢?我们跳转到 drop 的实现

    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn drop<T>(_x: T) { }
    

    对,它的函数体是空的!!!

    其实不难理解,因为 mb 被移动到 drop 中了,在 drop 函数结束后,mb.drop() 就会被调用 ,这样就实现了资源的提前释放。

  • 相关阅读:
    python_selenium 之logging模块入门及调用实战
    python_selenium 之yaml文件读取(以读取元素信息为例)
    python_selenium_PO模式下显示等待、隐式等待封装,结合Excel读取元素可取默认等待时间配置
    ubuntu WPS的安装
    ubuntu时间网络同步
    shell笔记
    for循环
    循环语句
    流程控制语句
    JavaScript数组
  • 原文地址:https://www.cnblogs.com/ywxt/p/rust_pointer_1.html
Copyright © 2020-2023  润新知