pub struct Arc<T>where
T: ?Sized,{ /* private fields */ }
Expand description
线程安全的引用计数指针。Arc
代表原子引用计数。
Arc<T>
类型提供了在堆中分配的 T
类型值的共享所有权。在 Arc
上调用 clone
会生成一个新的 Arc
实例,该实例指向堆上与源 Arc
相同的分配,同时增加了引用计数。
当指向给定分配的最后一个 Arc
指针被销毁时,存储在该分配中的值 (通常称为 “内部值”) 也将被丢弃。
默认情况下,Rust 中的共享引用不允许可变的,Arc
也不例外:您通常无法获得 Arc
内部内容的可变引用。如果需要通过 Arc
进行可变的,请使用 Mutex
,RwLock
或 Atomic
类型之一。
Note: 此类型仅在支持原子加载和指针存储的平台上可用,其中包括支持 std
crate 的所有平台,但并非所有仅支持 alloc
的平台。
这可以在编译时使用 #[cfg(target_has_atomic = "ptr")]
检测到。
线程安全
与 Rc<T>
不同,Arc<T>
使用原子操作进行引用计数。这意味着它是线程安全的。缺点是原子操作比普通的内存访问更昂贵。如果您不共享线程之间的引用计数分配,请考虑使用 Rc<T>
来降低开销。
Rc<T>
是一个安全的默认值,因为编译器会捕获在线程之间发送 Rc<T>
的任何尝试。
但是,一个库可能会选择 Arc<T>
,以便为库的消费者提供更大的灵活性。
只要 T
实现 Send
和 Sync
,Arc<T>
就会实现 Send
和 Sync
。
为什么不能在 Arc<T>
中放置非线程安全类型 T
使其成为线程安全的? 起初这可能有点违反直觉:毕竟,Arc<T>
的重点不就是线程安全吗? 关键在于: Arc<T>
使具有同一数据的多个所有权成为线程安全的,但并未为其数据增加线程安全。
考虑 Arc<RefCell<T>>
。
RefCell<T>
不是 Sync
,如果 Arc<T>
总是 Send
,那么 Arc<RefCell<T>>
也是。
但是然后我们会遇到一个问题:
RefCell<T>
不是线程安全的; 它使用非原子操作来跟踪借用计数。
最后,这意味着您可能需要将 Arc<T>
与某种 std::sync
类型 (通常为 Mutex<T>
) 配对。
Weak
的中断循环
downgrade
方法可用于创建非所有者 Weak
指针。Weak
指针可以 upgrade
为 Arc
,但如果存储在分配中的值已经被丢弃,这将返回 None
。
换句话说,Weak
指针不会使分配内部的值保持活动状态。然而,它们确实使分配(值的后备存储)保持活动状态。
Arc
指针之间的循环将永远不会被释放。
因此,Weak
用于中断循环。例如,一棵树可能具有从父节点到子节点的强 Arc
指针,以及从子节点返回到其父节点的 Weak
指针。
克隆引用
使用为 Arc<T>
和 Weak<T>
实现的 Clone
trait 从现有的引用计数指针创建新的引用。
use std::sync::Arc;
let foo = Arc::new(vec![1.0, 2.0, 3.0]);
// 以下两种语法是等效的。
let a = foo.clone();
let b = Arc::clone(&foo);
// a、b 和 foo 都是指向同一内存位置的 Arc
RunDeref
行为
Arc<T>
自动取消对 T
的引用 (通过 Deref
trait),因此您可以在类型为 Arc<T>
的值上调用 T
的方法。为了避免与 T
的方法名称冲突,Arc<T>
本身的方法是关联函数,使用 完全限定语法 调用:
use std::sync::Arc;
let my_arc = Arc::new(());
let my_weak = Arc::downgrade(&my_arc);
RunArc<T>
也可以使用完全限定语法来调用诸如 Clone
之类的 traits 实现。
有些人喜欢使用完全限定的语法,而另一些人则喜欢使用方法调用语法。
use std::sync::Arc;
let arc = Arc::new(());
// 方法调用语法
let arc2 = arc.clone();
// 完全限定的语法
let arc3 = Arc::clone(&arc);
RunWeak<T>
不会自动解引用到 T
,因为内部值可能已经被丢弃了。
Examples
在线程之间共享一些不可变数据:
use std::sync::Arc;
use std::thread;
let five = Arc::new(5);
for _ in 0..10 {
let five = Arc::clone(&five);
thread::spawn(move || {
println!("{five:?}");
});
}
Run共享可变的 AtomicUsize
:
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
let val = Arc::new(AtomicUsize::new(5));
for _ in 0..10 {
let val = Arc::clone(&val);
thread::spawn(move || {
let v = val.fetch_add(1, Ordering::SeqCst);
println!("{v:?}");
});
}
Run有关更多一般引用计数示例,请参见 rc
文档。
Implementations§
source§impl<T> Arc<T>
impl<T> Arc<T>
1.60.0 · sourcepub fn new_cyclic<F>(data_fn: F) -> Arc<T>where
F: FnOnce(&Weak<T>) -> T,
pub fn new_cyclic<F>(data_fn: F) -> Arc<T>where F: FnOnce(&Weak<T>) -> T,
创建一个新的 Arc<T>
,同时给您一个分配的 Weak<T>
,以允许您创建一个 T
,它持有一个指向自身的弱指针。
通常,直接或间接循环引用自身的结构体不应该对自身持有强引用以防止内存泄漏。
使用这个函数,您可以在 T
的初始化过程中,在 Arc<T>
创建之前访问弱指针,这样您就可以将它克隆并存储在 T
中。
new_cyclic
先给 Arc<T>
分配托管分配,然后调用您的闭包,给这个分配一个 Weak<T>
,然后再把您的闭包返回的 T
放入分配中,完成 Arc<T>
的构建。
由于新的 Arc<T>
在 Arc<T>::new_cyclic
返回之前尚未完全构造,因此在闭包内的弱引用上调用 upgrade
将失败并导致 None
值。
Panics
如果 data_fn
发生 panic,panic 会传播给调用者,而临时的 Weak<T>
会被正常丢弃。
Example
use std::sync::{Arc, Weak};
struct Gadget {
me: Weak<Gadget>,
}
impl Gadget {
/// 创建一个引用计数的 Gadget。
fn new() -> Arc<Self> {
// `me` 是指向我们正在构建的 `Arc` 的新分配的 `Weak<Gadget>`。
Arc::new_cyclic(|me| {
// 在此处创建实际的结构体。
Gadget { me: me.clone() }
})
}
/// 返回一个指向 Self 的引用计数指针。
fn me(&self) -> Arc<Self> {
self.me.upgrade().unwrap()
}
}
Runsourcepub fn new_uninit() -> Arc<MaybeUninit<T>>
🔬This is a nightly-only experimental API. (new_uninit
#63291)
pub fn new_uninit() -> Arc<MaybeUninit<T>>
new_uninit
#63291)sourcepub fn new_zeroed() -> Arc<MaybeUninit<T>>
🔬This is a nightly-only experimental API. (new_uninit
#63291)
pub fn new_zeroed() -> Arc<MaybeUninit<T>>
new_uninit
#63291)创建一个具有未初始化内容的新 Arc
,并用 0
字节填充内存。
有关正确和不正确使用此方法的示例,请参见 MaybeUninit::zeroed
。
Examples
#![feature(new_uninit)]
use std::sync::Arc;
let zero = Arc::<u32>::new_zeroed();
let zero = unsafe { zero.assume_init() };
assert_eq!(*zero, 0)
Run1.33.0 · sourcepub fn pin(data: T) -> Pin<Arc<T>>
pub fn pin(data: T) -> Pin<Arc<T>>
创建一个新的 Pin<Arc<T>>
。
如果 T
未实现 Unpin
,则 data
将被固定在内存中并且无法移动。
sourcepub fn try_pin(data: T) -> Result<Pin<Arc<T>>, AllocError>
🔬This is a nightly-only experimental API. (allocator_api
#32838)
pub fn try_pin(data: T) -> Result<Pin<Arc<T>>, AllocError>
allocator_api
#32838)创建一个新的 Pin<Arc<T>>
,如果分配失败则返回错误。
sourcepub fn try_new(data: T) -> Result<Arc<T>, AllocError>
🔬This is a nightly-only experimental API. (allocator_api
#32838)
pub fn try_new(data: T) -> Result<Arc<T>, AllocError>
allocator_api
#32838)sourcepub fn try_new_uninit() -> Result<Arc<MaybeUninit<T>>, AllocError>
🔬This is a nightly-only experimental API. (allocator_api
#32838)
pub fn try_new_uninit() -> Result<Arc<MaybeUninit<T>>, AllocError>
allocator_api
#32838)sourcepub fn try_new_zeroed() -> Result<Arc<MaybeUninit<T>>, AllocError>
🔬This is a nightly-only experimental API. (allocator_api
#32838)
pub fn try_new_zeroed() -> Result<Arc<MaybeUninit<T>>, AllocError>
allocator_api
#32838)创建一个具有未初始化内容的新 Arc
,并用 0
字节填充内存,如果分配失败,则返回错误。
有关正确和不正确使用此方法的示例,请参见 MaybeUninit::zeroed
。
Examples
#![feature(new_uninit, allocator_api)]
use std::sync::Arc;
let zero = Arc::<u32>::try_new_zeroed()?;
let zero = unsafe { zero.assume_init() };
assert_eq!(*zero, 0);
Run1.4.0 · sourcepub fn try_unwrap(this: Arc<T>) -> Result<T, Arc<T>>
pub fn try_unwrap(this: Arc<T>) -> Result<T, Arc<T>>
如果 Arc
正好有一个强引用,则返回内部值。
否则,返回的 Err
将与传入的 Arc
相同。
即使存在突出的弱引用,此操作也将成功。
如果您不想将 Arc
保留在 Err
外壳中,强烈建议改用 Arc::into_inner
。
立即抛弃 Err
有效,载荷,就像在表达式 Arc::try_unwrap(this).ok()
中一样,仍然可以导致强制使用计数抛弃为零,Arc
的内部值为抛弃:
例如,如果两个线程都在并行中执行这个表达式,那么就有一个竞争条件。
线程可以首先检查它们是否通过 Arc::try_unwrap
拥有它们的 Arc
的最后一个克隆,然后在调用中将它们的 Arc
丢弃到 ok
,将强引用计数从 2 降为零。
Examples
use std::sync::Arc;
let x = Arc::new(3);
assert_eq!(Arc::try_unwrap(x), Ok(3));
let x = Arc::new(4);
let _y = Arc::clone(&x);
assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4);
Run1.70.0 · sourcepub fn into_inner(this: Arc<T>) -> Option<T>
pub fn into_inner(this: Arc<T>) -> Option<T>
如果 Arc
正好有一个强引用,则返回内部值。
否则,返回 None
,Arc
为丢弃。
即使存在突出的弱引用,此操作也将成功。
如果在这个 Arc
的每个克隆上调用 Arc::into_inner
,则可以保证恰好有一个调用返回内部值。
这特别意味着内部值不是丢弃。
类似的表达式 Arc::try_unwrap(this).ok()
不提供这样的保证。
请参见下面的最后一个示例和 Arc::try_unwrap
的文档。
Examples
演示 Arc::into_inner
提供的保证的最小示例。
use std::sync::Arc;
let x = Arc::new(3);
let y = Arc::clone(&x);
// 两个线程在 `Arc` 的两个克隆上调用 `Arc::into_inner`:
let x_thread = std::thread::spawn(|| Arc::into_inner(x));
let y_thread = std::thread::spawn(|| Arc::into_inner(y));
let x_inner_value = x_thread.join().unwrap();
let y_inner_value = y_thread.join().unwrap();
// 其中一个线程保证接收到内部值:
assert!(matches!(
(x_inner_value, y_inner_value),
(None, Some(3)) | (Some(3), None)
));
// 如果线程改为调用 `Arc::try_unwrap(x).ok()` 和 `Arc::try_unwrap(y).ok()`,结果也可能是 `(None, None)`。
Run一个更实际的例子证明需要 Arc::into_inner
:
use std::sync::Arc;
// 使用 `Arc` 定义一个简单的单向链表:
#[derive(Clone)]
struct LinkedList<T>(Option<Arc<Node<T>>>);
struct Node<T>(T, Option<Arc<Node<T>>>);
// 丢掉依赖于 `Arc` 的析构函数的 long `LinkedList<T>` 会导致栈溢出。
// 为了防止这种情况,我们可以提供一个手动的 `Drop` 实现,它在循环中进行销毁:
impl<T> Drop for LinkedList<T> {
fn drop(&mut self) {
let mut link = self.0.take();
while let Some(arc_node) = link.take() {
if let Some(Node(_value, next)) = Arc::into_inner(arc_node) {
link = next;
}
}
}
}
// 省略 `new` 和 `push` 的实现
impl<T> LinkedList<T> {
/* ... */
}
// 如果 `Drop` impl 使用的是 `Arc::try_unwrap(arc).ok()` 而不是 `Arc::into_inner(arc)`,则尽管手动 `Drop` impl,以下代码仍可能导致栈溢出。
// 创建一个长列表并克隆它
let mut x = LinkedList::new();
for i in 0..100000 {
x.push(i); // 将 i 添加到 x 的前面
}
let y = x.clone();
// 丢弃并行中的克隆人
let x_thread = std::thread::spawn(|| drop(x));
let y_thread = std::thread::spawn(|| drop(y));
x_thread.join().unwrap();
y_thread.join().unwrap();
Runsource§impl<T> Arc<[T]>
impl<T> Arc<[T]>
sourcepub fn new_uninit_slice(len: usize) -> Arc<[MaybeUninit<T>]>
🔬This is a nightly-only experimental API. (new_uninit
#63291)
pub fn new_uninit_slice(len: usize) -> Arc<[MaybeUninit<T>]>
new_uninit
#63291)创建一个具有未初始化内容的新原子引用计数切片。
Examples
#![feature(new_uninit)]
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut values = Arc::<[u32]>::new_uninit_slice(3);
// 延迟初始化:
let data = Arc::get_mut(&mut values).unwrap();
data[0].write(1);
data[1].write(2);
data[2].write(3);
let values = unsafe { values.assume_init() };
assert_eq!(*values, [1, 2, 3])
Runsourcepub fn new_zeroed_slice(len: usize) -> Arc<[MaybeUninit<T>]>
🔬This is a nightly-only experimental API. (new_uninit
#63291)
pub fn new_zeroed_slice(len: usize) -> Arc<[MaybeUninit<T>]>
new_uninit
#63291)创建一个具有未初始化内容的新原子引用计数切片,内存中填充 0
字节。
有关正确和不正确使用此方法的示例,请参见 MaybeUninit::zeroed
。
Examples
#![feature(new_uninit)]
use std::sync::Arc;
let values = Arc::<[u32]>::new_zeroed_slice(3);
let values = unsafe { values.assume_init() };
assert_eq!(*values, [0, 0, 0])
Runsource§impl<T> Arc<MaybeUninit<T>>
impl<T> Arc<MaybeUninit<T>>
sourcepub unsafe fn assume_init(self) -> Arc<T>
🔬This is a nightly-only experimental API. (new_uninit
#63291)
pub unsafe fn assume_init(self) -> Arc<T>
new_uninit
#63291)转换为 Arc<T>
。
Safety
与 MaybeUninit::assume_init
一样,由调用者负责确保内部值确实处于初始化状态。
在内容尚未完全初始化时调用此方法会立即导致未定义的行为。
Examples
#![feature(new_uninit)]
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut five = Arc::<u32>::new_uninit();
// 延迟初始化:
Arc::get_mut(&mut five).unwrap().write(5);
let five = unsafe { five.assume_init() };
assert_eq!(*five, 5)
Runsource§impl<T> Arc<[MaybeUninit<T>]>
impl<T> Arc<[MaybeUninit<T>]>
sourcepub unsafe fn assume_init(self) -> Arc<[T]>
🔬This is a nightly-only experimental API. (new_uninit
#63291)
pub unsafe fn assume_init(self) -> Arc<[T]>
new_uninit
#63291)转换为 Arc<[T]>
。
Safety
与 MaybeUninit::assume_init
一样,由调用者负责确保内部值确实处于初始化状态。
在内容尚未完全初始化时调用此方法会立即导致未定义的行为。
Examples
#![feature(new_uninit)]
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut values = Arc::<[u32]>::new_uninit_slice(3);
// 延迟初始化:
let data = Arc::get_mut(&mut values).unwrap();
data[0].write(1);
data[1].write(2);
data[2].write(3);
let values = unsafe { values.assume_init() };
assert_eq!(*values, [1, 2, 3])
Runsource§impl<T> Arc<T>where
T: ?Sized,
impl<T> Arc<T>where T: ?Sized,
1.17.0 · sourcepub fn into_raw(this: Arc<T>) -> *const T
pub fn into_raw(this: Arc<T>) -> *const T
消耗 Arc
,返回包装的指针。
为避免内存泄漏,必须使用 Arc::from_raw
将指针转换回 Arc
。
Examples
use std::sync::Arc;
let x = Arc::new("hello".to_owned());
let x_ptr = Arc::into_raw(x);
assert_eq!(unsafe { &*x_ptr }, "hello");
Run1.17.0 · sourcepub unsafe fn from_raw(ptr: *const T) -> Arc<T>
pub unsafe fn from_raw(ptr: *const T) -> Arc<T>
从裸指针构造 Arc<T>
。
裸指针必须事先由调用返回到 Arc<U>::into_raw
,其中 U
的大小和对齐方式必须与 T
相同。
如果 U
是 T
,这是很简单的。
请注意,如果 U
不是 T
,但是具有相同的大小和对齐方式,则基本上就像对不同类型的引用进行转换一样。
有关在这种情况下适用的限制的更多信息,请参见 mem::transmute
。
from_raw
的用户必须确保 T
的特定值仅被丢弃一次。
此函数不安全,因为使用不当可能会导致内存不安全,即使从未访问返回的 Arc<T>
也是如此。
Examples
use std::sync::Arc;
let x = Arc::new("hello".to_owned());
let x_ptr = Arc::into_raw(x);
unsafe {
// 转换回 `Arc` 以防止泄漏。
let x = Arc::from_raw(x_ptr);
assert_eq!(&*x, "hello");
// 进一步调用 `Arc::from_raw(x_ptr)` 将导致内存不安全。
}
// 当 `x` 超出上面的作用域时,其内存将被释放,所以 `x_ptr` 现在悬垂了!
Run1.15.0 · sourcepub fn weak_count(this: &Arc<T>) -> usize
pub fn weak_count(this: &Arc<T>) -> usize
1.15.0 · sourcepub fn strong_count(this: &Arc<T>) -> usize
pub fn strong_count(this: &Arc<T>) -> usize
1.51.0 · sourcepub unsafe fn increment_strong_count(ptr: *const T)
pub unsafe fn increment_strong_count(ptr: *const T)
与提供的指针关联的 Arc<T>
上的强引用计数加 1。
Safety
指针必须已经通过 Arc::into_raw
获得,并且关联的 Arc
实例必须有效 (即
在此方法的持续时间内,强引用计数必须至少为 1)。
Examples
use std::sync::Arc;
let five = Arc::new(5);
unsafe {
let ptr = Arc::into_raw(five);
Arc::increment_strong_count(ptr);
// 此断言是确定性的,因为我们尚未在线程之间共享 `Arc`。
let five = Arc::from_raw(ptr);
assert_eq!(2, Arc::strong_count(&five));
}
Run1.51.0 · sourcepub unsafe fn decrement_strong_count(ptr: *const T)
pub unsafe fn decrement_strong_count(ptr: *const T)
将与提供的指针关联的 Arc<T>
上的强引用计数减 1。
Safety
指针必须已经通过 Arc::into_raw
获得,并且关联的 Arc
实例必须有效 (即
调用此方法时,强引用计数必须至少为 1)。
此方法可用于释放最终的 Arc
和后备存储,但不应在最终的 Arc
释放后调用。
Examples
use std::sync::Arc;
let five = Arc::new(5);
unsafe {
let ptr = Arc::into_raw(five);
Arc::increment_strong_count(ptr);
// 这些断言是确定性的,因为我们尚未在线程之间共享 `Arc`。
let five = Arc::from_raw(ptr);
assert_eq!(2, Arc::strong_count(&five));
Arc::decrement_strong_count(ptr);
assert_eq!(1, Arc::strong_count(&five));
}
Run1.17.0 · sourcepub fn ptr_eq(this: &Arc<T>, other: &Arc<T>) -> bool
pub fn ptr_eq(this: &Arc<T>, other: &Arc<T>) -> bool
如果两个 Arc
以类似于 ptr::eq
的方式指向相同的分配,则返回 true
。
比较 dyn Trait
指针时的注意事项,请参见 that function。
Examples
use std::sync::Arc;
let five = Arc::new(5);
let same_five = Arc::clone(&five);
let other_five = Arc::new(5);
assert!(Arc::ptr_eq(&five, &same_five));
assert!(!Arc::ptr_eq(&five, &other_five));
Runsource§impl<T> Arc<T>where
T: Clone,
impl<T> Arc<T>where T: Clone,
1.4.0 · sourcepub fn make_mut(this: &mut Arc<T>) -> &mut T
pub fn make_mut(this: &mut Arc<T>) -> &mut T
对给定的 Arc
进行可变引用。
如果有其他 Arc
指针指向同一分配,则 make_mut
会将内部值 clone
到新分配以确保唯一的所有权。
这也称为写时克隆。
但是,如果没有其他 Arc
指针指向这个分配,而是一些 Weak
指针,那么 Weak
指针将被分离,内部值不会被克隆。
另请参见 get_mut
,它将失败而不是克隆内部值或分离 Weak
指针。
Examples
use std::sync::Arc;
let mut data = Arc::new(5);
*Arc::make_mut(&mut data) += 1; // 不会克隆任何东西
let mut other_data = Arc::clone(&data); // 不会克隆内部数据
*Arc::make_mut(&mut data) += 1; // 克隆内部数据
*Arc::make_mut(&mut data) += 1; // 不会克隆任何东西
*Arc::make_mut(&mut other_data) *= 2; // 不会克隆任何东西
// 现在,`data` 和 `other_data` 指向不同的分配。
assert_eq!(*data, 8);
assert_eq!(*other_data, 12);
RunWeak
指针将被分离:
use std::sync::Arc;
let mut data = Arc::new(75);
let weak = Arc::downgrade(&data);
assert!(75 == *data);
assert!(75 == *weak.upgrade().unwrap());
*Arc::make_mut(&mut data) += 1;
assert!(76 == *data);
assert!(weak.upgrade().is_none());
Runsourcepub fn unwrap_or_clone(this: Arc<T>) -> T
🔬This is a nightly-only experimental API. (arc_unwrap_or_clone
#93610)
pub fn unwrap_or_clone(this: Arc<T>) -> T
arc_unwrap_or_clone
#93610)如果我们有 T
的唯一引用,那就打开它。否则,克隆 T
并返回克隆。
假设 arc_t
是 Arc<T>
类型,这个函数在功能上等同于 (*arc_t).clone()
,但会尽可能避免克隆内部值。
Examples
#![feature(arc_unwrap_or_clone)]
let inner = String::from("test");
let ptr = inner.as_ptr();
let arc = Arc::new(inner);
let inner = Arc::unwrap_or_clone(arc);
// 内部值没有被克隆
assert!(ptr::eq(ptr, inner.as_ptr()));
let arc = Arc::new(inner);
let arc2 = arc.clone();
let inner = Arc::unwrap_or_clone(arc);
// 因为有两个引用,我们不得不克隆内部值。
assert!(!ptr::eq(ptr, inner.as_ptr()));
// `arc2` 是最后一个引用,所以当我们展开它时,我们会得到原来的 `String`。
let inner = Arc::unwrap_or_clone(arc2);
assert!(ptr::eq(ptr, inner.as_ptr()));
Runsource§impl<T> Arc<T>where
T: ?Sized,
impl<T> Arc<T>where T: ?Sized,
sourcepub unsafe fn get_mut_unchecked(this: &mut Arc<T>) -> &mut T
🔬This is a nightly-only experimental API. (get_mut_unchecked
#63292)
pub unsafe fn get_mut_unchecked(this: &mut Arc<T>) -> &mut T
get_mut_unchecked
#63292)将变量引用返回给定的 Arc
,而不进行任何检查。
另请参见 get_mut
,它是安全的并且进行适当的检查。
Safety
如果存在指向同一分配的任何其他 Arc
或 Weak
指针,则在返回的借用期间,它们不得被解引用或具有活动借用,并且它们的内部类型必须与此 Rc 的内部类型完全相同 (包括生命周)。
如果不存在这样的指针 (例如紧接在 Arc::new
之后),则情况很简单。
Examples
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut x = Arc::new(String::new());
unsafe {
Arc::get_mut_unchecked(&mut x).push_str("foo")
}
assert_eq!(*x, "foo");
Run指向同一分配的其他 Arc
指针必须指向同一类型。
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let x: Arc<str> = Arc::from("Hello, world!");
let mut y: Arc<[u8]> = x.clone().into();
unsafe {
// 这是未定义的行为,因为 x 的内部类型是 str,而不是 [u8]
Arc::get_mut_unchecked(&mut y).fill(0xff); // 0xff 在 UTF-8 中无效
}
println!("{}", &*x); // str 中的 UTF-8 无效
Run指向同一分配的其他 Arc
指针必须指向完全相同的类型,包括生命周期。
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let x: Arc<&str> = Arc::new("Hello, world!");
{
let s = String::from("Oh, no!");
let mut y: Arc<&str> = x.clone().into();
unsafe {
// 这是未定义的行为,因为 x 的内部类型是 &'long str,而不是 &'short str
*Arc::get_mut_unchecked(&mut y) = &s;
}
}
println!("{}", &*x); // Use-after-free
Runsource§impl Arc<dyn Any + Send + Sync + 'static>
impl Arc<dyn Any + Send + Sync + 'static>
1.29.0 · sourcepub fn downcast<T>(self) -> Result<Arc<T>, Arc<dyn Any + Send + Sync + 'static>>where
T: Any + Send + Sync,
pub fn downcast<T>(self) -> Result<Arc<T>, Arc<dyn Any + Send + Sync + 'static>>where T: Any + Send + Sync,
尝试将 Arc<dyn Any + Send + Sync>
转换为具体类型。
Examples
use std::any::Any;
use std::sync::Arc;
fn print_if_string(value: Arc<dyn Any + Send + Sync>) {
if let Ok(string) = value.downcast::<String>() {
println!("String ({}): {}", string.len(), string);
}
}
let my_string = "Hello World".to_string();
print_if_string(Arc::new(my_string));
print_if_string(Arc::new(0i8));
Runsourcepub unsafe fn downcast_unchecked<T>(self) -> Arc<T>where
T: Any + Send + Sync,
🔬This is a nightly-only experimental API. (downcast_unchecked
#90850)
pub unsafe fn downcast_unchecked<T>(self) -> Arc<T>where T: Any + Send + Sync,
downcast_unchecked
#90850)将 Arc<dyn Any + Send + Sync>
向下转换为具体类型。
有关安全的替代方案,请参见 downcast
。
Examples
#![feature(downcast_unchecked)]
use std::any::Any;
use std::sync::Arc;
let x: Arc<dyn Any + Send + Sync> = Arc::new(1_usize);
unsafe {
assert_eq!(*x.downcast_unchecked::<usize>(), 1);
}
RunSafety
包含的值必须是 T
类型。
使用不正确的类型调用此方法是 未定义的行为。
Trait Implementations§
1.64.0 · source§impl<T: AsFd> AsFd for Arc<T>
impl<T: AsFd> AsFd for Arc<T>
这个 impl 允许在 Arc 上实现需要 AsFd
的 traits。
use std::net::UdpSocket;
use std::sync::Arc;
trait MyTrait: AsFd {}
impl MyTrait for Arc<UdpSocket> {}
impl MyTrait for Box<UdpSocket> {}
Runsource§fn as_fd(&self) -> BorrowedFd<'_>
fn as_fd(&self) -> BorrowedFd<'_>
1.71.0 · source§impl<T: AsHandle> AsHandle for Arc<T>
Available on Windows only.
impl<T: AsHandle> AsHandle for Arc<T>
这个 impl 允许在 Arc 上实现需要 AsHandle
的 traits。
use std::fs::File;
use std::sync::Arc;
trait MyTrait: AsHandle {}
impl MyTrait for Arc<File> {}
impl MyTrait for Box<File> {}
Runsource§fn as_handle(&self) -> BorrowedHandle<'_>
fn as_handle(&self) -> BorrowedHandle<'_>
1.63.0 · source§impl<T: AsRawFd> AsRawFd for Arc<T>
impl<T: AsRawFd> AsRawFd for Arc<T>
这个 impl 允许在 Arc 上实现需要 AsRawFd
的 traits。
use std::net::UdpSocket;
use std::sync::Arc;
trait MyTrait: AsRawFd {
}
impl MyTrait for Arc<UdpSocket> {}
impl MyTrait for Box<UdpSocket> {}
Run1.71.0 · source§impl<T: AsSocket> AsSocket for Arc<T>
Available on Windows only.
impl<T: AsSocket> AsSocket for Arc<T>
这个 impl 允许在 Arc 上实现需要 AsSocket
的 traits。
use std::net::UdpSocket;
use std::sync::Arc;
trait MyTrait: AsSocket {}
impl MyTrait for Arc<UdpSocket> {}
impl MyTrait for Box<UdpSocket> {}
Runsource§fn as_socket(&self) -> BorrowedSocket<'_>
fn as_socket(&self) -> BorrowedSocket<'_>
1.52.0 · source§impl<T> Error for Arc<T>where
T: Error + ?Sized,
impl<T> Error for Arc<T>where T: Error + ?Sized,
1.45.0 · source§impl<'a, B> From<Cow<'a, B>> for Arc<B>where
B: ToOwned + ?Sized,
Arc<B>: From<&'a B> + From<<B as ToOwned>::Owned>,
impl<'a, B> From<Cow<'a, B>> for Arc<B>where B: ToOwned + ?Sized, Arc<B>: From<&'a B> + From<<B as ToOwned>::Owned>,
1.37.0 · source§impl<T> FromIterator<T> for Arc<[T]>
impl<T> FromIterator<T> for Arc<[T]>
source§fn from_iter<I>(iter: I) -> Arc<[T]>where
I: IntoIterator<Item = T>,
fn from_iter<I>(iter: I) -> Arc<[T]>where I: IntoIterator<Item = T>,
获取 Iterator
中的每个元素,并将其收集到 Arc<[T]>
中。
性能特点
一般情况
在一般情况下,首先要收集到 Vec<T>
中来收集到 Arc<[T]>
中。也就是说,编写以下内容时:
let evens: Arc<[u8]> = (0..10).filter(|&x| x % 2 == 0).collect();
Run这就像我们写的那样:
let evens: Arc<[u8]> = (0..10).filter(|&x| x % 2 == 0)
.collect::<Vec<_>>() // 第一组分配在此处发生。
.into(); // `Arc<[T]>` 的第二个分配在此处进行。
Run这将分配构造 Vec<T>
所需的次数,然后分配一次,以将 Vec<T>
转换为 Arc<[T]>
。
已知长度的迭代器
当您的 Iterator
实现 TrustedLen
且大小正确时,将为 Arc<[T]>
进行一次分配。例如:
let evens: Arc<[u8]> = (0..10).collect(); // 这里只进行一次分配。
Run