Структура Weak

Weak - это версия Arc, которая содержит невладеющую ссылку на управляемое выделение памяти.

Описание

Выделение памяти доступно через вызов upgrade на указателе Weak, который возвращает Option<Arc<T>>.

Поскольку слабая ссылка не учитывается в праве владения, она не предотвращает удаление значения, хранящегося в выделенной памяти, и сам Weak не даёт гарантий, что значение всё ещё присутствует. Таким образом, он может вернуть None при вызове upgrade. Однако следует отметить, что слабая ссылка действительно предотвращает освобождение самой памяти (резервного хранилища).

Указатель Weak полезен для сохранения временной ссылки на выделение памяти, управляемое Arc, без предотвращения удаления его внутреннего значения. Он также используется для предотвращения циклических ссылок между указателями Arc, поскольку взаимные владеющие ссылки никогда не позволят удалить ни один из Arc. Например, дерево может иметь сильные указатели Arc от родительских узлов к дочерним и слабые указатели Weak от дочерних обратно к их родителям.

Типичный способ получить указатель Weak - вызвать Arc::downgrade.

Декларация

#![allow(unused)]
fn main() {
pub struct Weak<T, A = Global>
where
    A: Allocator,
    T: ?Sized,
{ /* private fields */ }
}

Методы

new (стабильно с версии 1.10.0, const с 1.73.0)

#![allow(unused)]
fn main() {
pub const fn new() -> Weak<T>
}

Создаёт новый Weak<T> без выделения памяти. Вызов upgrade на возвращаемом значении всегда даёт None.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::Weak;

let empty: Weak<i64> = Weak::new();
assert!(empty.upgrade().is_none());
}

new_in (только ночная версия, экспериментальное API)

#![allow(unused)]
fn main() {
pub fn new_in(alloc: A) -> Weak<T, A>
}

Создаёт новый Weak<T, A> без выделения памяти, технически в предоставленном аллокаторе. Вызов upgrade на возвращаемом значении всегда даёт None.

Примеры:

#![allow(unused)]
#![feature(allocator_api)]

fn main() {
use std::sync::Weak;
use std::alloc::System;

let empty: Weak<i64, _> = Weak::new_in(System);
assert!(empty.upgrade().is_none());
}

from_raw (стабильно с версии 1.45.0)

#![allow(unused)]
fn main() {
pub unsafe fn from_raw(ptr: *const T) -> Weak<T>
}

Преобразует сырой указатель, ранее созданный into_raw, обратно в Weak<T>.

Это можно использовать для безопасного получения сильной ссылки (вызовом upgrade позже) или для освобождения слабого счётчика путём удаления Weak<T>.

Он принимает владение одной слабой ссылкой (за исключением указателей, созданных new, так как они ничем не владеют; метод всё равно работает с ними).

Безопасность:

Указатель должен происходить из into_raw и всё ещё должен владеть своей потенциальной слабой ссылкой, и должен указывать на блок памяти, выделенный глобальным аллокатором.

Разрешено, чтобы сильный счётчик был 0 во время вызова этого метода. Тем не менее, это принимает владение одной слабой ссылкой, в настоящее время представленной как сырой указатель (слабый счётчик не изменяется этой операцией), и поэтому он должен быть сопряжён с предыдущим вызовом into_raw.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::{Arc, Weak};

let strong = Arc::new("hello".to_owned());

let raw_1 = Arc::downgrade(&strong).into_raw();
let raw_2 = Arc::downgrade(&strong).into_raw();

assert_eq!(2, Arc::weak_count(&strong));

assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap());
assert_eq!(1, Arc::weak_count(&strong));

drop(strong);

// Уменьшаем последний слабый счётчик.
assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none());
}

into_raw (стабильно с версии 1.45.0)

#![allow(unused)]
fn main() {
pub fn into_raw(self) -> *const T
}

Потребляет Weak<T> и превращает его в сырой указатель.

Это преобразует слабый указатель в сырой указатель, сохраняя владение одной слабой ссылкой (слабый счётчик не изменяется этой операцией). Его можно преобразовать обратно в Weak<T> с помощью from_raw.

Применяются те же ограничения доступа к цели указателя, что и с as_ptr.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::{Arc, Weak};

let strong = Arc::new("hello".to_owned());
let weak = Arc::downgrade(&strong);
let raw = weak.into_raw();

assert_eq!(1, Arc::weak_count(&strong));
assert_eq!("hello", unsafe { &*raw });

drop(unsafe { Weak::from_raw(raw) });
assert_eq!(0, Arc::weak_count(&strong));
}

allocator (только ночная версия, экспериментальное API)

#![allow(unused)]
fn main() {
pub fn allocator(&self) -> &A
}

Возвращает ссылку на базовый аллокатор.

as_ptr (стабильно с версии 1.45.0)

#![allow(unused)]
fn main() {
pub fn as_ptr(&self) -> *const T
}

Возвращает сырой указатель на объект T, на который указывает этот Weak<T>.

Указатель действителен только при наличии некоторых сильных ссылок. В противном случае указатель может быть висящим, невыровненным или даже null.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::Arc;
use std::ptr;

let strong = Arc::new("hello".to_owned());
let weak = Arc::downgrade(&strong);
// Оба указывают на один и тот же объект
assert!(ptr::eq(&*strong, weak.as_ptr()));
// Сильная ссылка здесь сохраняет его живым, поэтому мы всё ещё можем получить доступ к объекту.
assert_eq!("hello", unsafe { &*weak.as_ptr() });

drop(strong);
// Но больше нет. Мы можем вызвать weak.as_ptr(), но доступ к указателю приведёт к
// неопределённому поведению.
// assert_eq!("hello", unsafe { &*weak.as_ptr() });
}

into_raw_with_allocator (только ночная версия, экспериментальное API)

#![allow(unused)]
fn main() {
pub fn into_raw_with_allocator(self) -> (*const T, A)
}

Потребляет Weak<T>, возвращая обёрнутый указатель и аллокатор.

Это преобразует слабый указатель в сырой указатель, сохраняя владение одной слабой ссылкой (слабый счётчик не изменяется этой операцией). Его можно преобразовать обратно в Weak<T> с помощью from_raw_in.

Применяются те же ограничения доступа к цели указателя, что и с as_ptr.

Примеры:

#![allow(unused)]
#![feature(allocator_api)]
fn main() {
use std::sync::{Arc, Weak};
use std::alloc::System;

let strong = Arc::new_in("hello".to_owned(), System);
let weak = Arc::downgrade(&strong);
let (raw, alloc) = weak.into_raw_with_allocator();

assert_eq!(1, Arc::weak_count(&strong));
assert_eq!("hello", unsafe { &*raw });

drop(unsafe { Weak::from_raw_in(raw, alloc) });
assert_eq!(0, Arc::weak_count(&strong));
}

from_raw_in (только ночная версия, экспериментальное API)

#![allow(unused)]
fn main() {
pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Weak<T, A>
}

Преобразует сырой указатель, ранее созданный into_raw, обратно в Weak<T> в предоставленном аллокаторе.

Это можно использовать для безопасного получения сильной ссылки (вызовом upgrade позже) или для освобождения слабого счётчика путём удаления Weak<T>.

Он принимает владение одной слабой ссылкой (за исключением указателей, созданных new, так как они ничем не владеют; метод всё равно работает с ними).

Безопасность:

Указатель должен происходить из into_raw и всё ещё должен владеть своей потенциальной слабой ссылкой, и должен указывать на блок памяти, выделенный alloc.

Разрешено, чтобы сильный счётчик был 0 во время вызова этого метода. Тем не менее, это принимает владение одной слабой ссылкой, в настоящее время представленной как сырой указатель (слабый счётчик не изменяется этой операцией), и поэтому он должен быть сопряжён с предыдущим вызовом into_raw.

upgrade (стабильно с версии 1.4.0)

#![allow(unused)]
fn main() {
pub fn upgrade(&self) -> Option<Arc<T, A>>
where
    A: Clone,
}

Пытается повысить указатель Weak до Arc, откладывая удаление внутреннего значения в случае успеха.

Возвращает None, если внутреннее значение с тех пор было удалено.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::Arc;

let five = Arc::new(5);

let weak_five = Arc::downgrade(&five);

let strong_five: Option<Arc<_>> = weak_five.upgrade();
assert!(strong_five.is_some());

// Уничтожаем все сильные указатели.
drop(strong_five);
drop(five);

assert!(weak_five.upgrade().is_none());
}

strong_count (стабильно с версии 1.41.0)

#![allow(unused)]
fn main() {
pub fn strong_count(&self) -> usize
}

Получает количество сильных (Arc) указателей, указывающих на это выделение памяти.

Если self был создан с помощью Weak::new, это вернёт 0.

weak_count (стабильно с версии 1.41.0)

#![allow(unused)]
fn main() {
pub fn weak_count(&self) -> usize
}

Получает приблизительное количество указателей Weak, указывающих на это выделение памяти.

Если self был создан с помощью Weak::new, или если не осталось сильных указателей, это вернёт 0.

Точность:

Из-за особенностей реализации возвращаемое значение может отличаться на 1 в любую сторону, когда другие потоки манипулируют любыми Arc или Weak, указывающими на то же выделение памяти.

ptr_eq (стабильно с версии 1.39.0)

#![allow(unused)]
fn main() {
pub fn ptr_eq(&self, other: &Weak<T, A>) -> bool
}

Возвращает true, если два Weak указывают на одно и то же выделение памяти, аналогично ptr::eq, или если оба не указывают ни на какое выделение памяти (потому что они были созданы с помощью Weak::new()). Однако эта функция игнорирует метаданные указателей dyn Trait.

Примечания:

Поскольку это сравнивает указатели, это означает, что Weak::new() будет равен друг другу, даже если они не указывают ни на какое выделение памяти.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::Arc;

let first_rc = Arc::new(5);
let first = Arc::downgrade(&first_rc);
let second = Arc::downgrade(&first_rc);

assert!(first.ptr_eq(&second));

let third_rc = Arc::new(5);
let third = Arc::downgrade(&third_rc);

assert!(!first.ptr_eq(&third));
}

Сравнение Weak::new:

#![allow(unused)]
fn main() {
use std::sync::{Arc, Weak};

let first = Weak::new();
let second = Weak::new();
assert!(first.ptr_eq(&second));

let third_rc = Arc::new(());
let third = Arc::downgrade(&third_rc);
assert!(!first.ptr_eq(&third));
}

Реализации трейтов

Clone (стабильно с версии 1.4.0)

Реализован для Weak<T, A>, где A: Allocator + Clone, T: ?Sized.

  • Метод: clone(&self) -> Weak<T, A> - создаёт клон указателя Weak, который указывает на то же выделение памяти.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::{Arc, Weak};

let weak_five = Arc::downgrade(&Arc::new(5));

let _ = Weak::clone(&weak_five);
}

Debug (стабильно с версии 1.4.0)

Реализован для Weak<T, A>, где A: Allocator, T: ?Sized.

Default (стабильно с версии 1.10.0)

Реализован для Weak<T>.

  • Метод: default() -> Weak<T> - создаёт новый Weak<T> без выделения памяти. Вызов upgrade на возвращаемом значении всегда даёт None.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::Weak;

let empty: Weak<i64> = Default::default();
assert!(empty.upgrade().is_none());
}

Drop (стабильно с версии 1.4.0)

Реализован для Weak<T, A>, где A: Allocator, T: ?Sized.

  • Метод: drop(&mut self) - удаляет указатель Weak.

Примеры:

#![allow(unused)]
fn main() {
use std::sync::{Arc, Weak};

struct Foo;

impl Drop for Foo {
    fn drop(&mut self) {
        println!("dropped!");
    }
}

let foo = Arc::new(Foo);
let weak_foo = Arc::downgrade(&foo);
let other_weak_foo = Weak::clone(&weak_foo);

drop(weak_foo);   // Ничего не печатает
drop(foo);        // Печатает "dropped!"

assert!(other_weak_foo.upgrade().is_none());
}

Другие реализации трейтов

  • CloneFromCell для Weak<T>, где T: ?Sized
  • CoerceUnsized<Weak<U, A>> для Weak<T, A>, где T: Unsize<U> + ?Sized, A: Allocator, U: ?Sized
  • DispatchFromDyn<Weak<U>> для Weak<T>, где T: Unsize<U> + ?Sized, U: ?Sized
  • PinCoerceUnsized для Weak<T, A>, где A: Allocator, T: ?Sized
  • Send для Weak<T, A>, где T: Sync + Send + ?Sized, A: Allocator + Send
  • Sync для Weak<T, A>, где T: Sync + Send + ?Sized, A: Allocator + Sync
  • UseCloned для Weak<T, A>, где A: Allocator + Clone, T: ?Sized

Автоматические реализации трейтов

  • Freeze для Weak<T, A>, где A: Freeze, T: ?Sized
  • RefUnwindSafe для Weak<T, A>, где A: RefUnwindSafe, T: RefUnwindSafe + ?Sized
  • Unpin для Weak<T, A>, где A: Unpin, T: ?Sized
  • UnwindSafe для Weak<T, A>, где A: UnwindSafe, T: RefUnwindSafe + ?Sized

Blanket-реализации

Стандартные blanket-реализации для всех типов, такие как Any, Borrow<T>, From<T>, ToString и другие.