- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
智能指针(smart pointers)是一类数据结构,是拥有数据所有权和额外功能的指针。是指针的进一步发展 。
指针(pointer)是一个包含内存地址的变量的通用概念。这个地址引用,或 ” 指向”(points at)一些其 他数据 。引用以 & 符号为标志并借用了他们所 指向的值。除了引用数据没有任何其他特殊功能。它们也没有任何额外开销,所以在Rust中应用得最多.
智能指针是Rust中一种特殊的数据结构。它与普通指针的本质区别在于普通指针是对值的借用,而智能指针通常拥有对数据的所有权。并且可以实现很多额外的功能.
它提供了许多强大的抽象来帮助程序员管理内存和并发。其中一些抽象包括智能指针和内部可变性类型,它们可以帮助你更安全、更高效地管理内存,例如 Box<T> 用于在堆上分配值。 Rc<T> 是一种引用计数类型,可以实现数据的多重所有权。 RefCell<T> 提供内部可变性,可用于实现对同一数据的多个可变引用 。
它们在标准库中定义,可以用来更灵活地管理内存,智能指针的一个特点就是实现了Drop和Deref这两个trait。其中Drop trait中提供了drop方法,在析构时会去调用。Deref trait提供了自动解引用的能力,让我们在使用智能指针的时候不需要再手动解引用了 。
Box<T>
是最简单的智能指针,它允许你在堆上分配值并在离开作用域时自动释放内存。 Rc<T>
和 Arc<T>
是引用计数类型,它们允许多个指针指向同一个值。当最后一个指针离开作用域时,值将被释放。 Rc<T>
不是线程安全的,而 Arc<T>
是线程安全的。 内部可变性类型允许你在不可变引用的情况下修改内部值。Rust中有几种内部可变性类型,包括 Cell<T> , RefCell<T> 和 UnsafeCell<T> .
Cell<T>
是一个内部可变性类型,它允许你在不可变引用的情况下修改内部值。 Cell<T>
只能用于 Copy
类型,因为它通过复制值来实现内部可变性。 RefCell<T>
也是一个内部可变性类型,它允许你在不可变引用的情况下修改内部值。与 Cell<T>
不同, RefCell<T>
可以用于非 Copy
类型。它通过借用检查来确保运行时的安全性。 UnsafeCell<T>
是一个底层的内部可变性类型,它允许你在不可变引用的情况下修改内部值。与 Cell<T>
和 RefCell<T>
不同, UnsafeCell<T>
不提供任何运行时检查来确保安全性。因此,使用 UnsafeCell<T>
可能会导致未定义行为。 此外,Rust还提供了一种弱引用类型 Weak<T> ,它可以与 Rc<T> 或 Arc<T> 一起使用来创建循环引用。 Weak<T> 不会增加引用计数,因此它不会阻止值被释放.
Box<T>
Box<T> 是最简单的智能指针,它允许你在堆上分配值并在离开作用域时自动释放内存.
Box<T> 通常用于以下情况:
Box<T>
来在堆上分配内存。例如,递归类型通常需要使用 Box<T>
来分配内存。 Box<T>
来在堆上分配内存。这样可以避免栈溢出的问题。 Box<T>
。例如,当你需要将一个闭包传递给函数时,可以使用 Box<T>
来存储闭包。 总之,当你需要在堆上分配内存并管理其生命周期时,可以考虑使用 Box<T> .
下面是一个简单的例子:
fn
main() { let b = Box:: new( 5); println!(" b = {}", b); } 复制代码
这里定义了变量 b,其值是一个指向被分配在堆上的值 5 的 Box。这个程序会打印出 b = 5;在这个例子 中,我们可以像数据是储存在栈上的那样访问 box 中的数据。正如任何拥有数据所有权的值那样,当像 b 这样的 box 在 main 的末尾离开作用域时,它将被释放。这个释放过程作用于 box 本身(位于栈上) 和它所指向的数据(位于堆上).
但是 Box<T> 无法同时在多个地方对同一个值进行引用 。
enum List { Cons( i32, Box), Nil, } use crate::List::{Cons, Nil}; fn main() { let a = Cons( 5, Box:: new( Cons( 10, Box:: new(Nil)))); let b = Cons( 3, Box:: new(a)); let c = Cons( 4, Box:: new(a)); } 复制代码
编译会得出如下错误: error[E0382]: use of moved value: a ,因为b和c无法同时拥有a的所有权,这个时候我们要用 Rc<T> 。
Rc<T>
Reference Counted 引用计数 Rc<T> 是一个引用计数类型,它允许多个指针指向同一个值。当最后一个指针离开作用域时,值将被释放。 Rc<T> 不是线程安全的,因此不能在多线程环境中使用.
Rc<T> 通常用于以下情况:
Rc<T>
。解决了使用 Box<T>
共享数据时出现编译错误 Rc<T>
和 Weak<T>
来实现。 下面是一个简单的例子,演示如何使用 Rc<T> 来共享数据:
use std::rc::Rc; fn main() { let data = Rc:: new( vec![ 1, 2, 3]); let data1 = data. clone(); let data2 = data. clone(); println!( "data: {:?}", data); println!( "data1: {:?}", data1); println!( "data2: {:?}", data2); } 复制代码
这个例子中,我们使用 Rc::new 来创建一个新的 Rc<T> 实例。然后,我们使用 clone 方法来创建两个新的指针,它们都指向同一个值。由于 Rc<T> 实现了引用计数,所以当最后一个指针离开作用域时,值将被释放.
但是 Rc<T> 在多线程中容易引发线程安全问题,为了解决这个问题,又有了 Arc<T> 。
Arc<T>
Atomically Reference Counted 原子引用计数 Arc<T> 是一个线程安全的引用计数类型,它允许多个指针在多个线程之间共享同一个值。当最后一个指针离开作用域时,值将被释放.
Arc<T> 通常用于以下情况:
Arc<T>
,是 Rc<T>
的多线程版本。 Arc<T>
来实现。 下面是一个简单的例子,演示如何使用 Arc<T> 来在线程之间共享数据:
use std::sync::Arc
; use std::thread ; fn main() { let data = Arc::new(vec![ 1, 2, 3]) ; let data1 = data.clone() ; let data2 = data.clone() ; let handle1 = thread::spawn(move || { println!("data1: {:?}", data1) ; }) ; let handle2 = thread::spawn(move || { println!("data2: {:?}", data2) ; }) ; handle1.join().unwrap() ; handle2.join().unwrap() ; } 复制代码
这个例子中,我们使用 Arc::new 来创建一个新的 Arc<T> 实例。然后,我们使用 clone 方法来创建两个新的指针,它们都指向同一个值。接着,我们在线程中使用这些指针来访问共享数据。由于 Arc<T> 实现了线程安全的引用计数,所以当最后一个指针离开作用域时,值将被释放.
Weak<T>
弱引用类型 Weak<T> 是一个弱引用类型,它可以与 Rc<T> 或 Arc<T> 一起使用来创建循环引用。 Weak<T> 不会增加引用计数,因此它不会阻止值被释放.
当你希望创建一个循环引用时,可以使用 Rc<T> 或 Arc<T> 和 Weak<T> 来实现.
Weak<T> 通常用于以下情况:
当你希望观察一个值而不拥有它时,可以使用 Weak<T> 来实现。由于 Weak<T> 不会增加引用计数,所以它不会影响值的生命周期.
下面是一个简单的例子,演示如何使用 Rc<T> 和 Weak<T> 来创建一个循环引用:
use std::rc::{Rc, Weak}; struct Node { value: i32, next: Option<Rc<Node>>, prev: Option<Weak<Node>>, } fn main() { let first = Rc:: new(Node { value: 1, next: None, prev: None }); let second = Rc:: new(Node { value: 2, next: None, prev: Some(Rc:: downgrade(&first)) }); first.next = Some(second. clone()); } 复制代码
这个例子中,我们定义了一个 Node 结构体,它包含一个值、一个指向下一个节点的指针和一个指向前一个节点的弱引用。然后,我们创建了两个节点 first 和 second ,并使用 Rc::downgrade 方法来创建一个弱引用。最后,我们将两个节点连接起来,形成一个循环引用.
需要注意的是,由于 Weak<T> 不会增加引用计数,所以它不会阻止值被释放。当你需要访问弱引用指向的值时,可以使用 upgrade 方法来获取一个临时的强引用。如果值已经被释放,则 upgrade 方法会返回 None .
UnsafeCell<T>
UnsafeCell<T> 是一个底层的内部可变性类型,它允许你在不可变引用的情况下修改内部值。与 Cell<T> 和 RefCell<T> 不同, UnsafeCell<T> 不提供任何运行时检查来确保安全性。因此,使用 UnsafeCell<T> 可能会导致未定义行为.
由于 UnsafeCell<T> 是一个底层类型,它通常不直接用于应用程序代码。相反,它被用作其他内部可变性类型(如 Cell<T> 和 RefCell<T> )的基础.
下面是一个简单的例子,演示如何使用 UnsafeCell<T> 来修改内部值:
use std::cell::UnsafeCell
; fn main() { let x = UnsafeCell::new( 1) ; let y = &x ; let z = &x ; unsafe { *x.get() = 2 ; *y.get() = 3 ; *z.get() = 4 ; } println!("x: {}", unsafe { *x.get() }) ; } 复制代码
这个例子中,我们使用 UnsafeCell::new 来创建一个新的 UnsafeCell<T> 实例。然后,我们创建了两个不可变引用 y 和 z ,它们都指向同一个值。接着,在一个 unsafe 块中,我们使用 get 方法来获取一个裸指针,并使用它来修改内部值。由于 UnsafeCell<T> 实现了内部可变性,所以我们可以在不可变引用的情况下修改内部值.
需要注意的是,由于 UnsafeCell<T> 不提供任何运行时检查来确保安全性,所以使用它可能会导致未定义行为。因此,在大多数情况下,你应该使用其他内部可变性类型(如 Cell<T> 和 RefCell<T> ),而不是直接使用 UnsafeCell<T> .
Cell<T>
Cell<T> 是一个内部可变性类型,它允许你在不可变引用的情况下修改内部值。 Cell<T> 只能用于 Copy 类型,因为它通过复制值来实现内部可变性.
Cell<T> 通常用于以下情况:
Cell<T>
来实现内部可变性。 Cell<T>
来实现。 下面是一个简单的例子,演示如何使用 Cell<T>
来修改内部值:
use std::cell::Cell
; fn main() { let x = Cell::new( 1) ; let y = &x ; let z = &x ; x.set(2) ; y.set(3) ; z.set(4) ; println!("x: {}", x.get()) ; } 复制代码
这个例子中,我们使用 Cell::new 来创建一个新的 Cell<T> 实例。然后,我们创建了两个不可变引用 y 和 z ,它们都指向同一个值。接着,我们使用 set 方法来修改内部值。由于 Cell<T> 实现了内部可变性,所以我们可以在不可变引用的情况下修改内部值.
需要注意的是,由于 Cell<T> 通过复制值来实现内部可变性,所以它只能用于 Copy 类型。如果你需要在不可变引用的情况下修改非 Copy 类型的值,可以考虑使用 RefCell<T> .
RefCell<T>
RefCell<T> 是一个内部可变性类型,它允许你在不可变引用的情况下修改内部值。与 Cell<T> 不同, RefCell<T> 可以用于非 Copy 类型.
RefCell<T> 通过借用检查来确保运行时的安全性。当你尝试获取一个可变引用时, RefCell<T> 会检查是否已经有其他可变引用或不可变引用。如果有,则会发生运行时错误.
RefCell<T> 通常用于以下情况:
当你需要在不可变引用的情况下修改内部值时,可以使用 RefCell<T> 来实现内部可变性.
当你需要在结构体中包含一个可变字段时,可以使用 RefCell<T> 来实现.
下面是一个简单的例子,演示如何使用 RefCell<T> 来修改内部值:
use std::cell::RefCell
; fn main() { let x = RefCell::new(vec![ 1, 2, 3]) ; let y = &x ; let z = &x ; x.borrow_mut().push(4) ; y.borrow_mut().push(5) ; z.borrow_mut().push(6) ; println!("x: {:?}", x.borrow()) ; } 复制代码
这个例子中,我们使用 RefCell::new 来创建一个新的 RefCell<T> 实例。然后,我们创建了两个不可变引用 y 和 z ,它们都指向同一个值。接着,我们使用 borrow_mut 方法来获取一个可变引用,并使用它来修改内部值。由于 RefCell<T> 实现了内部可变性,所以我们可以在不可变引用的情况下修改内部值.
需要注意的是,由于 RefCell<T> 通过借用检查来确保运行时的安全性,所以当你尝试获取一个可变引用时,如果已经有其他可变引用或不可变引用,则会发生运行时错误。from刘金,转载请注明原文链接。感谢! 。
最后此篇关于Rust中的智能指针:BoxRcArcCellRefCellWeak的文章就讲到这里了,如果你想了解更多关于Rust中的智能指针:BoxRcArcCellRefCellWeak的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我知道您可以使用 -fno-objc-arc 标志对 ARC 项目中不支持 ARC 的文件禁用 ARC。 有什么方法可以在非 ARC 项目中为支持 ARC 的文件启用 ARC 吗? 谢谢! 最佳答案
ARC 代表自动引用计数。 我刚刚升级了我的项目以使用 ARC。虽然不是全部。只是一些。 我怎么知道? 最佳答案 要查看默认值,您必须检查目标属性(您的目标 -> build设置 -> Apple L
我有一个框架 A,它是 ARC。这会消耗一些来自非 ARC 框架 B 的 API。 框架B示例代码(非ARC): @interface Settings : NSObject { NSDict
我一直避免升级 Xcode,直到某个特定项目完成(即将推出)。我希望能够在未来的项目中使用 ARC,同时保留维护和调查先前软件产品问题的能力。 问题是可以通过安装一次 Xcode 来完成此操作吗?当我
我正在开发一个非常旧的非基于 ARC 的项目,并添加了一些基于 ARC 的新 UIViewController(可以通过在构建阶段设置 -fobjc-arc 标志来实现) . 由于ARC和非ARC的混
这个问题在这里已经有了答案: How do you enable ARC project-wide in Xcode 4.2 (3 个答案) How to automatically conver
我是 iPhone 开发的新手。我了解到ARC是现在IOS引入的新特性。我的问题是,我有一个手动编写版本的旧非 ARC 项目,是否可以将该项目从非 ARC 切换到 ARC ? 谢谢, 拉吉 最佳答案
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 7年前关闭。 Improve this questi
我的项目是在 ARC 打开的情况下创建的,现在我使用的是第三方框架,该框架很可能不是用 ARC 构建的。这样做会有什么问题吗?我现在遇到了框架中某个地方发生的崩溃,但我没有得到有关崩溃的太多详细信息。
我猜这是一个简单的问题,但我无法弄清楚: 我的项目中存在三个与构建阶段中设置的链接器标志 -fno-obj-arc 不 ARC 兼容的文件。 但是据我所知,这些标志被忽略了。编译器仍然提示向对象发送保
我认为标题很好地解释了我的问题,我目前正在开发一个满足我个人需求的小型框架,并考虑使用 ARC 构建它(如果可能的话?),并在旧项目中使用它是在 ARC 之前 build 的吗? 最佳答案 是的,但有
我正在努力让现有的启用 ARC 的控件在不启用 ARC 的项目中在 Xcode 4.2 (OSX Snow Leopard) 下运行,并且我面临着各种问题: 我应该如何解决以下问题? 在属性中使用(s
我想知道如何更改 Arc 中的值,然后使 Arc 的其他副本再次有效。 use std::sync::Arc; use std::thread; use std::error::Error; use
ARC 运行时版本:我不知道,但我在这个网站上下载了它,https://chrome.google.com/webstore/detail/arc-welder/emfinbmielocnlhgmfk
当我将 iPhone 项目转换为 Objective - c ARC 时,我总是遇到相同的错误: /Applications/Xcode.app/Contents/Developer/Platform
如何在没有 ARC 的情况下为使用 ARC 的项目构建静态库? 我找到了一些静态库的源代码,我想为我的项目构建它,但我使用的是 ARC。 最佳答案 静态库可以在没有 ARC 的情况下构建,并且可以使用
我有一个使用 ARC 的 A 类和不使用 ARC 的其他 B 类和 C 类。如果 A 包含 B 类对象而 B 包含 C 类对象,那么 ARC 如何工作以及当 B 类和 C 类中的内存管理处理不当时会发
一旦我将 -fno-objc-arc 标志添加到构建阶段中的一个或多个单独的文件,我的 MyProject-Prefix.pch 文件就会进入非 ARC 模式,导致 150 条警告,如“警告:没有‘分
在某些情况下,我需要为几个非 ARC xcode 项目中的许多文件启用 ARC。我不想完全转换为 ARC,只需要使用 arc 启用几个文件。 有许多解决方案使用 XCode 控制台将 -fobjc-a
我还没有使用过 ARC,只是在它通过第 3 方代码强制进入项目时处理它。我已经阅读了所有 ARC 文档,但还没有看到这个问题的答案: 如果我在使用 -fobjc-arc 编译的模块中定义了一个类,我能
我是一名优秀的程序员,十分优秀!