前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2023学习日志

2023学习日志

原创
作者头像
TomoriNao
发布2023-07-27 21:29:01
1340
发布2023-07-27 21:29:01
举报
文章被收录于专栏:每月技术成长每月技术成长

rust

智能指针

Box<T>指针

  • 堆上存储数据,而指针本身位于栈上 Box<T>类型的智能指针创建的是指向堆数据的指针,初始化过程中,会将数据分配在堆上,能够有效地节省栈上有限的空间,在所有权转移的过程中,复制的仅仅是一个栈上的指针,而非实际的数据,能够提高程序的性能 示例:
代码语言:rust
复制
    fn main() {
        let b = Box::new(5);
        println!("b = {}",b);
    }
  • 允许创建递归类型 对于常见的cons list类型的数据结构(嵌套的列表),如果直接在声明结构体时进行嵌套,rust的编译器无法推断出该类型数据占用的内存大小,会在编译时报错。 示例:
代码语言:rust
复制
//编译时将报错,无法推断出List结构体的具体大小
    use crate::List::{Cons, Nil};
    enum List{
        Cons(i32,List),
        Nil,
    }
    fn main(){
        let list = Cons(1, Cons(2, Cons(3, Nil)));
    }

此时可以使用Box<T>指针指向嵌套的列表,得到cons list类型的结构体。(指针的内存大小是已知的,但列表的大小是在进行结构体声明时未知的)

示例:

代码语言:rust
复制
// 此段代码不会报错,因为Box<T>为智能指针,大小固定,编译器可以推断出List类型的大小
    use crate::List::{Cons, Nil};
    enum List{
        Cons(i32, Box<List>),
        Nil
    }
    fn main(){
        let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
    }
  • 超出作用域之后,自动释放堆上数据 在超出作用域后,栈上的数据都会被逐一清除,而Box<T>智能指针在清除之前会调用其实现了的Drop trait的drop函数,清除所指向的堆上的数据。

Deref Trait 重载解引用运算符

智能指针类型的变量本身为指针类型,在使用时需要进行解引用来得到其所指向的数据。而解引用需要重载解引用运算符&。而通过实现Deref Trait,能够将类型像引用一样处理。

Deref trait需要实现其定义的deref方法,返回一个内部数据的引用

示例:

代码语言:rust
复制
    //为Mybox<T>类型实现Deref trait
    use std::ops::Deref;
    impl<T> Deref for MyBox<T> {
        type Target = T;
        fn deref(&self) -> &self::Target {
            &self.0
        }
    }
    struct MyBox<T>(T);
    impl<T> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox(x)
        }
    }
    fn main() {
        let x=5;
        let y = MyBox::new(x);
        assert_eq!(5, x);
        assert_eq!(5, *y);
    }

Drop Trait 自动清除数据

Drop trait 类似于c++中的析构函数,在变量离开作用域时调用,清除数据或进行一些其他操作。

实现Drop trait需要实现其drop方法,该方法在变量离开时被调用,完成指定的一些操作。(主要目的为清理该变量拥有的数据)

此外,还可通过std::mem::drop 来在作用域结束前释放变量,std::mem::drop位于prelude中,因此无需显式引入该方法

示例:

代码语言:rust
复制
    //为CustomSmartPointer结构体实现Drop trait
    struct CustomSmartPointer {
        data: String,
    }
    impl Drop for CustomSmartPointer {
        fn drop (&mut self){
            println!("Droping CustomSmartPointer with Data `{}`", self.data);
        
        }
    }
    fn main() {
        let c = CustomSmartPointer{
            data: String::from("my stuff"),
        };
        drop(c);
        let d = CustomSmartPointer{
            data: String::from("other stuff"),
        };
        println!("CustomSmartPointer created.");
    }

Rc<T>指针

Rc<T> 用于当我们希望在堆上分配一些数据供程序的多个部分读取,且无法在编译时确定程序的哪一部分会最终结束使用它的时候,如果确实知道哪部分是最后结束使用的话,可以令其成为数据的所有者,正常的所有权规则在编译时生效。

可以通过克隆Rc<T>的方式获取对堆上数据的引用,每次克隆时,引用计数增加1,当一个Rc<T>指针离开作用域时,引用计数减1,而当引用计数为0时,对应的drop方法将会被调用,堆上数据将会被清理。

注意:Rc<T>克隆的结果为不可变引用rust不允许同时存在多个可变引用

  • 强引用 --Rc<T> Rc<T>指针强引用,可以通过调用Rc::clone方法返回一个Rc<T>指针,会导致引用计数发生变化,当引用计数为0时,指针所指向的堆上数据将会被清理
  • 弱引用 --Weak<T> Weak<T>指针弱引用,可以通过Rc::downgrade方法返回一个*Weak<T>指针,不会导致引用计数发生变化,不会对堆上数据的清理产生影响 因为Weak<T>引用的值可能已经被丢弃了,因此需要在使用Weak<T>所指向的值时,调用Weak<T>实例的upgrade方法,返回一个Option<Rc<T>>

示例:

代码语言:rust
复制
    use crate::List::{Cons, Nil};
    use std::rc::Rc;
    enum List {
        Cons(i32, Rc<List>),
        Nil,
    }
    fn main(){
        let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
        println!("count after creating a = {}", Rc::strong_count(&a));
        //Rc::clone得到的是Rc<T>类型的强引用,会影响引用计数
        let b = Cons(3, Rc::clone(&a));
        println!("count after creating b =  {}", Rc::strong_count(&a));
        {
            let c = Cons(4, Rc::clone(&a));
            println!("count after creating c = {}", Rc::strong_count(&a));
        }
        println!("count after c goes out of scope = {}", Rc::strong_count(&a));
    }

RefCell<T>指针

  • 内部可变性 内部可变性rust中的一个设计模式,它允许你即使在有不可变引用时也可以改变数据,这通常是借用规则不允许的。该模式使用unsafe代码来模糊rust可变性借用规则。 当可以确保代码在运行时会遵守借用规则,即使是编译器无法保证的情况,可以选择使用运用了内部可变性模式的类型。
  • RefCell<T>运行时检查借用规则 RerCell<T>遵循内部可变性模式,在运行时检查借用规则而非编译时。 因为RefCell<T>允许在运行时检查借用规则,因此可以在RefCell自身不可变的情况修改其内部的值。 示例:
代码语言:rust
复制
    use std::cell::RefCell;
    trait Messenger {
        fn send(&self, msg: &str);
    }
    struct MockMessenger {
        sent_messages: RefCell<Vec<String>>,
    }
    impl Messager for MockMessenger {
        fn send(&self, message: &str) {
            //borrow_mut()方法获取的是RefMut<T>类型的智能指针,borrow()方法获取的是Ref<T>类型的智能指针
            self.sent_message.borrow_mut().push(String::from(message));
        }
    }
  • RefCell<T>在运行时记录借用 borrow_mut方法获取的是RefMut<T>类型的智能指针,borrow方法获取的是Ref<T>类型的智能指针 RefCell<T>记录当前有多少个活动的Ref<T>RefMut<T>智能指针,每次调用borrow方法,RefCell<T>将不可变借用计数加一,当Ref<T>指针离开作用域时,不可变计数减一。可变借用计数规则类似不可解压计数规则。 与编译时借用规则相同:RefCell<T>在任何时刻只允许存在多个不可变借用一个可变借用。 示例:
代码语言:rust
复制
    impl Messenger for MockMessenger {
        fn send(&self, message: &str){
            //代码将报错,不能同时存在两个可变借用
            let mut one_borrow = self.sent_message.borrow_mut();
            let mut two_borrow = self.sent_message.borrow_mut();
        }
    }

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • rust
    • 智能指针
      • Box<T>指针
      • Deref Trait 重载解引用运算符
      • Drop Trait 自动清除数据
      • Rc<T>指针
      • RefCell<T>指针
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com