Rust- 智能指针

这篇具有很好参考价值的文章主要介绍了Rust- 智能指针。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Smart pointers

A smart pointer is a data structure that not only acts like a pointer but provides additional functionality. This “smartness” comes from the fact that smart pointers encapsulate additional logical or semantic rules, which are automatically applied to simplify memory or resource management tasks.

While different programming languages implement smart pointers in various ways, they all share a common goal: to manage the life cycle of the resources they point to.

Here are some key features of smart pointers:

  1. Ownership: Smart pointers keep track of the memory they point to, and can automatically reclaim (or “free”) that memory when it’s no longer needed. This can greatly simplify memory management, as the programmer doesn’t need to manually release memory, reducing the risk of memory leaks.

  2. Reference Counting: Some smart pointers, like the Rc<T> in Rust or shared_ptr in C++, keep a count of the number of references (i.e., pointers) to an object. This object is only deallocated when there are no more references to it.

  3. Dereferencing: Like regular pointers, smart pointers implement the dereferencing operation, allowing access to the data they point to.

  4. Polymorphism: In object-oriented languages, smart pointers can be used to enable polymorphism when pointing to base and derived class objects.

  5. Thread Safety: Some smart pointers, like Arc<T> in Rust or std::atomic_shared_ptr in C++20, are thread-safe, meaning they can be safely used in concurrent programming.

In Rust, smart pointers are essential components due to the language’s focus on safety and zero-cost abstractions. Box<T>, Rc<T>, and RefCell<T> are some of the commonly used smart pointers in Rust.

  1. Box<T>: This is the simplest kind of smart pointer. It allows you to put data on the heap rather than the stack. Box<T> is often used in Rust in two scenarios: when you have a type of known size but need to store a value of a type that might have an unknown size at compile time, or when you have a large data item and want to transfer ownership to a function without copying the data to prevent stack overflow.

  2. Rc<T>: “Rc” stands for reference counting. The Rc<T> smart pointer allows your program to have multiple read-only references to the same data item on the heap. It keeps track of the number of references to the data on the heap, and once the reference count goes to zero, meaning there are no more references to the data, it cleans up the data.

  3. RefCell<T>: Rust performs borrow checking at compile time which ensures that references to data obey the rules of either one write or multiple reads. However, sometimes you may need to do such checking at runtime. RefCell<T> provides this functionality. This means that while you can borrow mutable references at runtime, your program will panic if you violate the rules of one write or multiple reads.

These are some of the basic smart pointers in Rust. There are several other smart pointers, like Arc<T>, Mutex<T>, etc., which are all designed to deal with ownership and concurrency issues in Rust.

It’s worth noting that while these types are called “smart pointers”, they’re not limited to mimicking pointer-like behavior. They’re actually more general constructs often used to add structure to a value, such as tracking reference counts, thread-safe access, and more.

Box< T >

Box<T> is a very important smart pointer in Rust. It allows you to store data on the heap rather than the stack. This is mainly used in Rust for the following two scenarios:

  1. Moving data to the heap: By default, Rust stores data on the stack. However, stack space is limited and the data on the stack is immediately removed when it goes out of scope. If you need to store a large amount of data in memory or need to pass data between scopes without losing ownership, you can use Box<T> to move the data to the heap.

  2. Storing dynamically sized types: In Rust, the size of all types must be known at compile time. However, there might be cases where you want to store a type whose size is not known at compile time. Box<T> can be used in this case, as the size of Box<T> itself is known regardless of the size of the data on the heap it points to.

When using Box<T>, Rust will automatically clean up the data on the heap when the Box<T> goes out of scope, meaning you do not need to manually manage memory.

Here is a simple example of Box<T>:

fn main() {
    let b = Box::new(5); // b is a pointer to a box in the heap
    println!("b = {}", b);
}

In this example, the integer 5 is stored on the heap, rather than on the stack. The variable b is a pointer to the value stored on the heap. When b goes out of scope, Rust’s automatic memory management system cleans up the data on the heap, so you do not need to manually free the memory.

use std::ops::Deref;
fn main() {
    /*
        如果一个结构体实现了deref和drop的Trait,那他们就不是普通结构体了。
        Rust提供了堆上存储数据的能力并把这个能力封装到了Box中。
        把栈上的数据搬到堆上的能力,就叫做装箱。

        Box可以把数据存储到堆上,而不是栈上,box 装箱,栈还是包含指向堆上数据的指针。
     */
    let a = 6;
    let b = Box::new(a);
    println!("b = {}", b); // b = 6

    let price1 = 158;
    let price2 = Box::new(price1);
    println!("{}", 158 == price1);  // true
    println!("{}", 158 == *price2); // true

    let x = 666;
    let y = CustomBox::new(x);

    println!("666 == x is {}", 666 == x);   // 666 == x is true
    println!("666 == *y is {}", 666 == *y); // 666 == *y is true
    println!("x == *y is {}", x == *y);     // x == *y is true
}

struct CustomBox<T> {
    value: T
}

impl <T> CustomBox<T> {
    fn new(v: T) -> CustomBox<T> {
        CustomBox { value: v }
    }
}

impl <T> Deref for CustomBox<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.value
    }
}

impl <T> Drop for CustomBox<T> {
    fn drop(&mut self) {
        println!("drop CustomBox 对象!")
    }
}

Rc < T >

Rc<T> stands for ‘Reference Counting’. It’s a smart pointer that allows you to have multiple owners of the same data. When each owner goes out of scope, the reference count is decreased. When the count reaches zero, the data is cleaned up.

Here’s a simple example:

use std::rc::Rc;

fn main() {
    let data = Rc::new("Hello, World!"); // data now has a reference count of 1

    {
        let _clone = Rc::clone(&data); // data now has a reference count of 2
        println!("Inside the scope, data is: {}", *_clone);
    } // _clone goes out of scope and data's reference count decreases to 1

    println!("Outside the scope, data is: {}", *data);
} // data goes out of scope and its reference count decreases to 0, the data is cleaned up

RefCell < T >

RefCell<T> provides ‘interior mutability’, a design pattern in Rust that allows you to mutate data even when there are immutable references to that data. It enforces the borrowing rules at runtime instead of compile time.

Here’s a simple example:

use std::cell::RefCell;

fn main() {
    let data = RefCell::new(5);

    {
        let mut mutable_reference = data.borrow_mut();
        *mutable_reference += 1;
        println!("Inside the scope, data is: {}", *mutable_reference);
    } // mutable_reference goes out of scope, the lock is released

    println!("Outside the scope, data is: {}", *data.borrow());
}

In this example, you can see that we borrowed a mutable reference to the data inside RefCell using borrow_mut, modified it, and then the lock was automatically released when the mutable reference went out of scope. This demonstrates the dynamic checking that RefCell<T> provides.

Note1: The borrow_mut() function is a method of RefCell<T> in Rust. This function is used to gain mutable access to the underlying value that the RefCell wraps around.

The RefCell struct in Rust enforces the borrow rules at runtime, allowing you to have multiple immutable references or one mutable reference at any point in time. If you attempt to violate these rules, your program will panic at runtime.

When you call borrow_mut() on a RefCell, you get a RefMut smart pointer that allows mutable access to the underlying data. Once this RefMut is dropped (which happens automatically when it goes out of scope), others can then borrow the RefCell again.

Here’s an example:

use std::cell::RefCell;

fn main() {
    let data = RefCell::new(5);

    {
        let mut mutable_reference = data.borrow_mut();
        *mutable_reference += 1;
        println!("Inside the scope, data is: {}", *mutable_reference);
    } // mutable_reference goes out of scope, the lock is released

    println!("Outside the scope, data is: {}", *data.borrow());
}

In this example, mutable_reference is a mutable reference to the integer wrapped in data, which is a RefCell. We increment the integer by 1, and after mutable_reference goes out of scope, we can borrow data again.

Note2: The borrow() function is a method of RefCell<T> in Rust. This function is used to gain immutable access to the underlying value that the RefCell wraps around.

Similar to borrow_mut(), it provides a way to access the data inside the RefCell. The difference is that borrow() gives you an immutable reference (Ref<T>), while borrow_mut() gives you a mutable reference (RefMut<T>).

The RefCell checks at runtime to make sure the borrowing rules are not violated, which are:

  1. You may have either one mutable reference or any number of immutable references at the same time, but not both.
  2. References must always be valid.

If you try to call borrow() when the value is already mutably borrowed (through borrow_mut()), or try to call borrow_mut() when the value is immutably borrowed (through borrow()), your program will panic at runtime.

Here’s how you might use borrow():

use std::cell::RefCell;

fn main() {
    let data = RefCell::new(5);

    {
        let mutable_reference = data.borrow_mut();
        *mutable_reference += 1;
    } // mutable_reference goes out of scope, the lock is released

    let immutable_reference = data.borrow();
    println!("Data is: {}", *immutable_reference);
} 

In this example, we first use borrow_mut() to mutate the value inside data, then we use borrow() to get an immutable reference to the data.文章来源地址https://www.toymoban.com/news/detail-620380.html

到了这里,关于Rust- 智能指针的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Rust- 智能指针

    A smart pointer is a data structure that not only acts like a pointer but provides additional functionality. This “smartness” comes from the fact that smart pointers encapsulate additional logical or semantic rules, which are automatically applied to simplify memory or resource management tasks. While different programming languages implement smart point

    2024年02月14日
    浏览(36)
  • rust 智能指针

    Rust中基本数据类型(如整数、浮点数、布尔值等)通常存储在栈上。而动态分配的数据,如 BoxT 和 VecT 等,存储在堆上。 Rust 中 Box 是一种智能指针类型,通常用于将值放置在堆上而不是栈上。在 Rust 中,由于所有值的默认生命周期都在当前作用域结束时结束,因此在情况需

    2024年02月06日
    浏览(77)
  • 【跟小嘉学 Rust 编程】十五、智能指针

    【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学 Rust 编程】六、枚举

    2024年02月11日
    浏览(43)
  • Rust编程语言入门之智能指针

    指针:一个变量在内存中包含的是一个地址(指向其它数据) Rust 中最常见的指针就是”引用“ 引用: 使用 借用它指向的值 没有其余开销 最常见的指针类型 智能指针是这样一些数据结构: 行为和指针相似 有额外的元数据和功能 通过记录所有者的数量,使一份数据被多个

    2023年04月16日
    浏览(38)
  • 【Rust 基础篇】Rust 的 `Rc<RefCell<T>>` - 共享可变性的智能指针

    在 Rust 中, RcRefCellT 是一种组合智能指针,用于实现多所有权共享可变数据。 Rc 允许多个所有者共享相同的数据,而 RefCell 允许在有多个引用的情况下对数据进行可变操作。 本篇博客将详细介绍 Rust 中 RcRefCellT 的使用方法和相关概念,以及它在代码中的应用场景。 RcRefCell

    2024年02月16日
    浏览(30)
  • 【Rust】——通过Deref trait将智能指针当作常规引用处理

    💻博主现有专栏:                 C51单片机(STC89C516),c语言,c++,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux,基于HTML5的网页设计及应用,Rust(官方文档重点总结),jQuery,前端vue.js,Javaweb开发,Python机器学习等 🥏主页链接:     

    2024年04月26日
    浏览(27)
  • rust 自动化测试、迭代器与闭包、智能指针、无畏并发

    编写测试可以让我们的代码在后续迭代过程中不出现功能性缺陷问题;理解迭代器、闭包的函数式编程特性; BoxT 智能指针在堆上存储数据, RcT 智能指针开启多所有权模式等;理解并发,如何安全的使用线程,共享数据。 编写测试以方便我们在后续的迭代过程中,不会改坏

    2024年02月16日
    浏览(33)
  • Rust踩雷笔记(5)——刷点链表的题(涉及智能指针Box,持续更新)

    只能说Rust链表题的画风和C++完全不一样,作为新手一时间还不太适应,于是单独为链表、智能指针开一篇,主要记录leetcode相关题型的答案以及注意事项。 🍑关键操作 as_ref() 将 OptionT 、 OptionT 或者 mut OptionT 转换为 OptionT as_mut() 将 OptionT 、 mut OptionT 转换为 Optionmut T ,不能对

    2024年02月11日
    浏览(24)
  • Rust中的函数指针

    通过函数指针允许我们使用函数作为另一个函数的参数。函数的类型是 fn (使用小写的 ”f” )以免与 Fn 闭包 trait 相混淆。fn 被称为 函数指针(function pointer)。指定参数为函数指针的语法类似于闭包。 函数指针类型(使用  fn  写出)指向那些在编译时不必知道函

    2024年02月02日
    浏览(30)
  • Rust语言中级教程之指针

    指针是计算机引用无法立即直接访问的数据的一种方式(类比 书的目录) 数据在物理内存(RAM)中是分散的存储着 地址空间是检索系统 指针就被编码为内存地址,使用 usize 类型的整数表示。 一个地址就会指向地址空间中的某个地方 地址空间的范围是 OS 和 CPU 提供的外观界

    2024年02月02日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包