Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Тема
Описание
Доп.

Несколько «владеющих» указателей на одни и те же данные

Тип Rc<T> обеспечивает совместное владение значением типа T, размещенным в куче.

Rc<T> — это указатель со счётчиком ссылок, он позволяет создавать несколько «владеющих» указателей на одни и те же данные, и эти данные будут уничтожены, когда все указатели выйдут из области видимости т.е. strong count =0.

Rc не допускает мутации. Чтобы разрешить это, нам нужно обернуть нашу оболочку Rc<RefCell<T>> - это тип, который можно использовать для выполнения внутренней изменяемости.

Не использовать в циклических структурах, для этих целей Weak

Совместное владение решает проблему необходимости разделения данных между несколькими частями программы без явного копирования.

Это особенно полезно в следующих случаях:

Разделение данных между несколькими структурами: Когда одна и та же область памяти должна быть доступна для нескольких структур или компонентов одновременно.

Избежание дублирования данных: Сокращает необходимость копировать большие объемы данных, что экономит память и время на копирование.

Гибкость в архитектуре программ: Позволяет создавать более гибкие и модульные структуры данных, где несколько частей программы могут ссылаться на одни и те же данные.

Однако это приводит к дополнительным накладным расходам на управление памятью, потенциальным проблемам с производительностью и сложностям при мутации данных.

Счетчик ссылок Reference Counted

Ключевым моментом является размещение значения за интеллектуальным указателем, чтобы сам указатель можно было клонировать много раз (что позволяет нескольким владельцам), но он всегда указывает на одно и то же значение (таким образом, разделяя значение).

Rc позволяет писать шаблоны, где мы не можем решить, когда запускать деструктор во время компиляции.

Мы используем Rc, когда хотим выделить некоторые данные в куче только для чтения в разных частях нашей программы, и во время компиляции мы не можем определить, какая часть закончит использование последей эти данные Когда счетчик ссылок равен 0 данные освобождаются

Rc отличие от Box и clone()

rust-trait-objects-box-and-rc

Rc, в отличие от этого Box, не копирует весь контекст и данные при вызове clone, он только копирует и передает ссылку на объект в куче, «толстый указатель» с виртуальной таблицей, указывающей на правильную реализацию типа Т.

Наши объекты должны быть, Sized если мы хотим использовать clone метод.

При вызове clone нам не нужно знать размер объекта, который мы копируем.

Единственное, что мы копируем, это ссылка на объект, живущий в куче, и мы увеличиваем счетчик 1.

use std::rc::Rc;
pub struct Server {
    engine: Rc<Engine>,
}
impl Default for Server {
    fn default() -> Self{
        // Instantiate a default Engine client
        let client = Rc::new(Docker::new());
        Server {
            engine: client,
        }
    }
}
impl Server {
    pub fn new() -> Server{
        Default::default()
    }
    // Overrides the default engine
    pub fn init_engine(&mut self, engine: Rc<Engine>)-> &mut Server{
        self.engine = engine;
        self
    }
    // [...] collection of init functions
    pub fn build(&self) -> Server{
        Server { engine: self.engine.clone()}
    }
}

Пример различия чтения файла с Rc и без

разница в том что Rc считает владельцев и уничтожает данные после последнего а &mut не владеет данными


#![allow(dead_code)]
use std::rc::Rc;
use std::fs::File;
use std::path::Path;
use std::io::Read;
fn rc_start_read(path: &Path)-> std::io::Result<()>{
    let mut file = File::open(path)?;
    let mut file_content:std::vec::Vec = Vec::new();
    file.read_to_end(&mut file_content)?;
 
    let mut rc_file_content = Rc::new(file_content);
// с правом собственности и без клонирования всего содержимого файла каждый раз
    rc_read(Rc::clone(&rc_file_content));
    rc_read(Rc::clone(&rc_file_content));
    rc_read(Rc::clone(&rc_file_content));
    rc_read(Rc::clone(&rc_file_content));
    rc_read(Rc::clone(&rc_file_content));
   println!("{:?}",file_content); Ошибка данные уничтожены после последней ссылки
    Ok(())
}
fn rc_read(buffer:Rc>){
    let content:std::borrow::Cow = String::from_utf8_lossy(&buffer);
    println!("{:?}",content.len());
    //println!("{:?}",content.into_owned());
}
/// без разделения ссылки
fn start_read(path: &Path)-> std::io::Result<()>{
    let mut file = File::open(path)?;
    let mut file_content:std::vec::Vec = Vec::new();
    file.read_to_end(&mut file_content)?;
// без права собственности по разделяемой ссылке
    read( &mut file_content);
    read( &mut file_content);
    read( &mut file_content);
    read( &mut file_content);
    read( &mut file_content);
   println!("{:?}",file_content); // Доступны
    Ok(())
}
fn read(buffer:&mut Vec){
    let content:std::borrow::Cow = String::from_utf8_lossy(&buffer);
    println!("{:?}",content.len());
    //println!("{:?}",content.into_owned());
}
fn main(){
    let path = std::path::Path::new("war_and_peace.pdf");
    // c Rc
    rc_start_read(&path);
    // без Rc
    start_read(&path);
}

Deref

impl<T> Clone for Rc<T> - Rc::clone(&x) не клонирует исходное значение, а скорее дает новую ссылку на него

impl From<String> for Rc<str>

Разделяется между несколькими владельцами, уникальной ссылки быть не может


use std::rc::Rc;
fn main() {
    let original: String = "statue".to_owned();
    let shared: Rc = Rc::from(original);
    let rc_shared: Rc = Rc::clone(&shared);
    let rc_shared2: Rc = Rc::clone(&shared);
    let cap:String = rc_shared2.repeat(4); // Deref
}

Совместное владение с внутренней изменчивостью и динамически проверенными правилами заимствования.

impl<T> Borrow<T> for Rc<T>

Rc<RefCell<String>>


use std::rc::Rc;
use std::borrow::Borrow;
use std::cell::RefCell;
fn main() {
    let rc:Rc> = Rc::new(RefCell::new("hello".to_string()));
    let rc_shared = Rc::clone(&rc);
   
    let rw_rc_borro:&RefCell = Rc::borrow(&rc);
    (*rw_rc_borro.borrow_mut()).push_str("..."); 

    let rw_rc_borro:&RefCell = Rc::borrow(&rc_shared);
    (*rw_rc_borro.borrow_mut()).push_str("***"); 

    assert_eq!("hello...***".to_string(), (*rc).take());
}

Методы:

  • downcast() - Попытайтесь привести Rc<dyn Any> к конкретному типу
  • downcast_unchecked() - Приводит Rc<dyn Any> к конкретному типу без проверки
  • downgrade() ->Weak<T> - Создает новый Weak указатель
  • get_mut()->Option<&mut T> - Возвращает изменяемую ссылку на данные, если нет других указателей
  • get_mut_unchecked()->&mut T Возвращает изменяемую ссылку на данные без проверки.
  • make_mut()->&mut T - Создает изменяемую ссылку на данную Rc при наличии других ссылок создаст clone

  • into_inner()->Option<T> - Расходует и возвращает внутреннее значение, если существует ровно одна strong ссылка.
  • try_unwrap()->Result<T, Rc<T>> - Возвращает внутреннее значение, если у Rc ровно одна strong ссылка
  • unwrap_or_clone()->T - Возвращает T при единственной ссылке. В противном случае верните клон T

  • strong_count() - количество strong указателей
  • weak_count() - количество weak указателей
  • decrement_strong_count() - Уменьшает счетчик strong ссылок Rc<T> на на единицу
  • increment_strong_count() - Увеличивает счетчик strong ссылок Rc<T> на на единицу

  • new() - Создает новый Rc<T>
  • new_cyclic() - Создает новый Rc<T> и предоставляя вам Weak<T> ссылающийся на самого себя
  • new_uninit() - Создает Rc с неинициализированным содержимым
  • new_uninit_slice() - Создает Rc slice с подсчетом ссылок с неинициализированным содержимым.
  • new_zeroed() - Создает Rc с неинициализированным содержимым при этом память заполняется 0 байтами.
  • new_zeroed_slice() - как new_uninit_slice при этом память заполняется 0 байтами.
  • pin() - Создает новый Pin<Rc<T>>

  • ptr_eq() - проверка указывают ли Rc на одно и то же распределение
  • as_ptr()-> *const T - Предоставляет необработанный указатель на данные.
  • from_raw() - Создает Rc<T> из необработанного указателя.
  • into_raw()-> *const T - Потребляет Rc, возвращая завернутый указатель (+using Rc::from_raw)
  • assume_init()

  • try_new() - Создает новый Rc<T>, возвращая ошибку, если выделение не удалось.
  • try_new_uninit()
  • try_new_zeroed()

Rc::new() - Создает новый Rc<T>


fn main(){
    use std::rc::Rc;
    let x:Rc = Rc::new(5);
}

Rc::downcast() - Попытайтесь привести Rc<dyn Any> к конкретному типу


fn main(){
use std::any::Any;
use std::rc::Rc;
fn main(){
    if let Ok(mut dialog) = Rc::downcast::(mediator) { .... }
}


fn print_if_string(value: Rc) {
    if let Ok(string) = value.downcast::() {
        println!("String ({}): {}", string.len(), string);
    }
}
fn main(){
    let my_string = "Hello World".to_string();
    print_if_string(Rc::new(my_string));
    print_if_string(Rc::new(0i8));
}

Rc::try_unwrap() Возвращает внутреннее значение, если у Rc ровно одна strong ссылка


fn main(){
    // В противном случае возвращается Err с тем же Rc, который был передан.
    match Rc::try_unwrap(x){
         Ok(n) => println!("Ok:{}",n),
         Err(e) => println!("{}",e)
    }
    let x = Rc::new(4);
    let _y = Rc::clone(&x);// создает новую ссылку на данные

    //if Rc::strong_count(&x) < 2 {
            match Rc::try_unwrap(x){
                Ok(n) => println!("Ok:{}",n),
                Err(e) => println!("Err {}",e)//Err 4
            }
    //}
    // assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4);
}

Rc::weak_count() Получает количество слабых указателей на это значение. Rc::strong_count() Получает число сильных (Rc) указателей на это значение


fn main(){
    let x = Rc::new(5);
    let weak_five = Rc::downgrade(&x);
    println!("weak_count={}",Rc::weak_count(&x));
    println!("strong_count={}",Rc::strong_count(&x));
}


fn main(){
// ссылки удаляются
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    println!("count after creating a = {}", Rc::strong_count(&a));// 1
    let b = Cons(3, Rc::clone(&a));
    println!("count after creating b = {}", Rc::strong_count(&a));// 2
    {
        let c = Cons(4, Rc::clone(&a));
        println!("count after creating c = {}", Rc::strong_count(&a));// 3
    }
    println!("count after c goes out of scope = {}", Rc::strong_count(&a));// 2
}

Rc::into_raw()->*const T - Расходует Rc, возвращая обернутый указатель Rc::from_raw - Обратное преобразование в указатель

Чтобы избежать утечки памяти, указатель должен быть преобразован обратно в Rc, используя Rc::from_raw


fn main(){
    let x = Rc::new(10);
    let x_ptr:*const i32 = Rc::into_raw(x);
    assert_eq!(unsafe { *x_ptr }, 10);

    //Rc::from_raw обратное преобразование в указатель
    unsafe {
        // Чтобы предотвратить утечку, вернитесь к `Rc`
        let x = Rc::from_raw(x_ptr);
        assert_eq!(*x, 10);
        // Дальнейшие вызовы `Rc :: from_raw (x_ptr)` будут опасны для памяти.
    }
}

Rc::ptr_eq() - Возвращает true, если две Rc указывают на одно и то же значение


fn main(){
    let five = Rc::new(5);
    let same_five = Rc::clone(&five);
    let other_five = Rc::new(5);

    assert!(Rc::ptr_eq(&five, &same_five));
    assert!(!Rc::ptr_eq(&five, &other_five));
}

Rc::make_mut() Возвращает измененную ссылку на внутреннее значение, если есть другие указатели Rc или Weak на данные сделает клонированием на запись, чтобы обеспечить уникальное право собственности.

В отличие от Rc::get_mut() который не создаст clone


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

    *Rc::make_mut(&mut data) += 1;        //data=6  Не будет клонировать ничего
    let mut other_data = Rc::clone(&data);// Не будет клонировать внутренние данные
    //  `data` и` other_data` еще указывают на одно значение.
    *Rc::make_mut(&mut data) += 1;        //other_data=6 data=7  Внутренние данные сколонировал .
    // Теперь `data` и` other_data` указывают на разные значения.
    *Rc::make_mut(&mut data) += 1;        //other_data=6 data=8  Не будет клонировать ничего
    *Rc::make_mut(&mut other_data) *= 2;  //other_data=12  Не будет клонировать ничего

//  Теперь `data` и` other_data` указывают на разные значения.
    assert_eq!(*data, 8);
    assert_eq!(*other_data, 12);
}

Получение не мутабельной и мутабельной ссылки на данные

Borrow и get_mut()


use std::cell::{RefCell, Ref, RefMut};
use std::rc::Rc;
fn main(){
    let mut r:Rc> = Rc::new(RefCell::new("hello".to_owned()));
    {
        // Rс реализует трейт Borrow т.е. можно получить не мутабельную ссылку
        let ref_cell:Ref = r.borrow();
        let s:String = (&ref_cell).to_string(); 
        println!("{}",s);
    }
    // Rc получение мутабельной ссылки
    let ref_cell_mut:RefMut = r.borrow_mut();
    let s:String = (&ref_cell_mut).to_string();
    println!("{}",s);

// или так , но один вариант будет отрабатывать,два раза мутабельную ссылку Rc невзять
// Rc получение мутабельной ссылки 
    if let Some(r_mut) = Rc::get_mut(&mut r){
       let s:&String = &*r_mut.borrow();
       println!("{}",s);
    }
}


struct Node{
   left:Option>
}
fn main(){
    if let Some(n) = &mut self.left{
         (*Rc::::get_mut(n).unwrap()).your_mut_method(node);
    }
}

Тут Rc методы напрямую не участвуют, по идее срабатывает Borrow. Rc получение не мутабельной ссылки.


pub fn search(&self,key:&str)->Option<&Node>{
    if let Some(node_rc) = self.nodes.get(key){ 
        if let Ok(node_ref) = node_rc.try_borrow(){// impl RefCell fn try_borrow() 
            return Some(std::cell::Ref::leak(node_ref));
        }
    }
    None
}
fn main(){
    let mut nodes: HashMap>> = HashMap::new();
    let node_new:Rc> = Rc::new(RefCell::new(node));
    nodes.insert("key".to_string(), node_new);
}

Rc::get_mut() Возвращает измененную ссылку на внутреннее значение, если нет других указателей Rc или Weak для одного и того же значения иначе None


fn main(){
    let mut x = Rc::new(3);
        //let _y = Rc::clone(&x);
    if Rc::strong_count(&x)==1 && Rc::weak_count(&x)==0 {
        let y = Rc::get_mut(&mut x);// получим None если есть еще указатель
        match y {
            Some(v) => {*v+=1; println!("Some={}",v)},
            None => println!("None")
        }
    }

    let mut x = Rc::new(3);
    *Rc::get_mut(&mut x).unwrap() = 4;
    assert_eq!(*x, 4);

    //let _y = Rc::clone(&x);
    //assert!(Rc::get_mut(&mut x).is_none());
}

Пример с графом владеют точкой "a" все ребра a,b,c

Граф a 5->10->Nil b 3->a c 4->a


fn main(){
    //enum List { Cons(i32, Box), Nil, }
    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));
}

use std::rc::Rc;
use List::{Cons, Nil};
enum List { Cons(i32, Rc),Nil } ✅
fn main(){
// Вызов Rc::clone только увеличивает счетчик ссылок,и не копирует данные и не занимает много времени в отличии от a.clone
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    let b = Cons(3, Rc::clone(&a));
    let c = Cons(4, Rc::clone(&a));
}
digraph { 5 -> 10 -> Nil 3 -> 5 4 -> 5 }

enum List {
    Cons(i32, Rc),
    Nil,
}

use List::{Cons, Nil};
use std::rc::Rc;

fn main() {
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    let b = Cons(3, Rc::clone(&a));
    let c = Cons(4, Rc::clone(&a));
}

Weak - для предотвращения зацикливания ссылок

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

Т.е. если значение на которое ссылается Weak будет удаленно(так как он не увеличивает strong ссылки) то ссылаться будет на Weak(None)

Weak указатели - это те, которые не увеличивают счетчик ссылок.

Это не владеющий, но и не заимствуемый, умный указатель.

Он тоже похож на &T, но не ограничен временем жизни — Weak<T> можно не отпускать.

Однако, возможна ситуация, когда попытка доступа к хранимым в нём данным провалится и вернёт None, поскольку Weak<T> может пережить владеющие Rc.

Его удобно использовать в случае циклических структур данных и некоторых других.

Чтобы сделать что-либо со значением, которое указывает на Weak<T>, мы должны убедиться, что значение все еще существует. Мы делаем это, вызывая метод Weak<T>::upgrade , который будет возвращать Option<Rc<T>>. Мы получим результат, Some если еще не было сброшено, и результат, None если значение было сброшено. Поскольку upgrade возвращает a Option<T>, Rust гарантирует, что мы обработаем Some случай и None случай, и не будет недействительных указаний

Однако, следует использовать Rc с умом , он не будет освобождать память (утечка памяти) при зациклить ссылки. Rust не может предотвратить утечки памяти во время компиляции (хотя и затрудняет их создание). Если по-прежнему требуется цикл ссылок, вы должны использовать Weak интеллектуальный указатель («слабую ссылку») в сочетании с Rc. Weak позволяет прервать цикл ссылок, поскольку может ссылаться на значение, которое уже было отброшено ( None в таком случае возвращается ).

Что происходит, когда вам нужна ссылка на общий объект, но вы не хотите владеть им. То есть вы не хотите, чтобы объект оставался живым? Вы создаете Weak ссылку на него. Эта ссылка не дает вам доступа к ресурсу, он им не принадлежит! Вместо этого он может попытаться upgrade превратиться в полную Rc или такую, которая им владеет.

Создание эталонных циклов непросто, но это тоже невозможно. Если у вас есть RefCell<T> значения, содержащие Rc<T> значения или похожие вложенные комбинации типов с внутренней изменчивостью и подсчетом ссылок, вы должны убедиться, что вы не создаете циклы; вы не можете полагаться на Rust, чтобы поймать их.

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

Методы:

  • as_ptr() - Возвращает необработанный указатель *const T на объект
  • from_raw() - Преобразует сырой указатель *const T ранее созданный into_raw сзади в Weak<T>
  • into_raw() - Принимает Weak<T> и превращает его в необработанный указатель *const T
  • new() - Создает новый объект Weak<T> без выделения памяти.
  • ptr_eq() - Возвращает значение true, если два Weaks указывают на одно и то же выделение
  • strong_count() - Получает количество сильных (Rc) указателей, указывающих на это выделение
  • weak_count() - Получает количество Weak указателей, указывающих на это выделение.
  • upgrade() - Пытается обновить Weak указатель до Rc

Weak::new() - Создает новый Weak , выделяя память для T без инициализации

Вызов обновления по возвращаемому значению всегда дает None


fn main(){            
    use std::rc::Weak;
    let empty: Weak = Weak::new();
    assert!(empty.upgrade().is_none());
}

Weak::upgrade() - Попытка обновить Weak указатель до Rc, увеличивая время жизни значения в случае успеха. Возвращает None, если значение с тех пор было сброшено.


use std::rc::Rc;
fn main(){
    let five = Rc::new(5);
    let weak_five = Rc::downgrade(&five);

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

    // Destroy all strong pointers.
    drop(strong_five);
    drop(five);
    assert!(weak_five.upgrade().is_none());

    //self.weatherData:Weak>>
    if let Some(weatherData:Rc>>) = self.weatherData.upgrade(){
        let weatherData = weatherData.borrow();
        self.temperature = weatherData.getTemperature();
    }
}

Weak::ptr_eq() - Возвращает, true если два Weaks указывают на одно и то же выделение (аналогично ptr::eq)


use std::rc::Rc;
fn main(){
    let first_rc = Rc::new(5);
    let first = Rc::downgrade(&first_rc);
    let second = Rc::downgrade(&first_rc);

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

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

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

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


use std::rc::{Rc, Weak};
fn main(){
    let first = Weak::new();
    let second = Weak::new();
    assert!(first.ptr_eq(&second));

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

Пример как получить доступ к данным Rc и Weak

#![feature(get_mut_unchecked)]
#[derive(Debug)]     
struct Person(String);
impl Person{
    fn show(&self){
        println!("{}",self.0);
    }
    fn get_key(&self)->&str{
        self.0.as_str()
    }
    fn set_key(&mut self,key:&str){
        self.0=key.to_owned();
    }
}

fn main(){
    let mut r:Rc<Person> = Rc::new(Person("hello".to_string()));
    {
        // Доступ к данным.Для Rc работает Deref поэтому можно обращаться к данным на прямую
        r.show();
        // для мутации данных находящихся за Rc используется Rc::get_mut или Rc::get_mut_unchecked в unsafe с #![feature(get_mut_unchecked)] и `cargo +nightly`
        if Rc::strong_count(&r)==1 && Rc::weak_count(&r)==0 {
            if let Some(person_mut) = Rc::get_mut(&mut r){
                person_mut.set_key("new key");
            } 
        }
        let key:&str = r.get_key();
        assert_eq!("new key",key);     
    }

    {
        // Доступ к данным.Для Weak нужно распаковывать через as_ptr или into_raw в Rc
        let weak:Weak<Person> = Rc::downgrade(&r);
        let p:&Person = unsafe { &*weak.as_ptr() };
        p.show();
        // Для изменения данных находящихся за Weak следует перевести weak обратно в Rc и использовать Rc::get_mut_unchecked в unsafe  с #![feature(get_mut_unchecked)] и `cargo +nightly`
        if let Some(ref mut r_mut) = weak.upgrade(){ 
            unsafe {
                let person_mut:&mut Person = Rc::get_mut_unchecked(r_mut);
                person_mut.set_key("new key 2");
            }   
        }
        let key:&str = p.get_key();
        assert_eq!("new key 2",key); 
    }
}

Rc::downgrade() - Создает новый слабый указатель на это значение.


use std::rc::{Rc,Weak};
#[derive(Debug)]
struct Node{
    name:String,
    value:Option>
}
impl Node{
    fn new(name:String)->Self{
        Self{name,value:None}
    }
    fn set_value(&mut self,value:Rc){
        self.value = Some(Rc::downgrade(&value));
    }
}
impl Drop for Node {
    fn drop(&mut self) {
        println!("Drop {}", &self.name);
    }
}
// С файлом Weak. Вы должны превратить его в Rc(или Arc) сначала использовать upgrade.
// И это либо удастся (если Tон все еще есть), либо нет

// Если у вас есть Weak, вы не можете напрямую получить доступ к его содержимому.
// Сначала вам нужно обновить его до Rc использования upgrade метода, который дает вам, Some(Rc) если контент все еще жив, или None если контент был уничтожен (сильное значение счетчика ссылок равно нулю).
// Итак, чтобы получить доступ к содержимому Weak, вы сначала должны получить Rc,
// и это гарантирует вам, что содержимое не будет уничтожено, пока вы его используете, поскольку у него есть по крайней мере один владелец.
fn main(){
    {
        let mut node = Node::new("Node 1".into());
        let mut node2 = Node::new("Node 2".into());
        let rc = Rc::new(node2);
        node.set_value(Rc::clone(&rc));
        // все слабые указатели Weak еще могут получить владеющий указатель Rc, так как он еще жив 
        let w:&Weak = node.value.as_ref().unwrap();
        if let Some(w) =  w.upgrade(){
            println!("{}",w.name);
        }
        assert!( w.upgrade().is_some());
    }
    {
        let mut node = Node::new("Node 1".into());
        let mut node2 = Node::new("Node 2".into());
        let rc = Rc::new(node2);
        node.set_value(Rc::clone(&rc));
        drop(rc);// после удаления владеющего указателя, все его Weak указатели так же удалились 
        let w:&Weak = node.value.as_ref().unwrap();
        assert!( w.upgrade().is_none());
    }
    
}

Пример создания слабого указателя

cargo +nightly run


#![feature(get_mut_unchecked)]
use std::rc::{Rc,Weak};

    #[derive(Debug)] 
    struct Test(String);
    impl Test{
        fn set_value(&mut self,value:String){
            self.0 = value;
        }
    }
fn main(){
    let test = Test("hello".to_string());
    // New Strong count
    let mut test_rc:Rc = Rc::new(test);
    assert_eq!(1,Rc::strong_count(&test_rc));// ++
    assert_eq!(0,Rc::weak_count(&test_rc));
    // изменение данных
    if Rc::strong_count(&test_rc)==1 && Rc::weak_count(&test_rc)==0 {
        if let Some(test) = Rc::get_mut(&mut test_rc){
            test.set_value("gfg".to_string());
            println!("{:?}",test_rc);
        } 
    }
 
    // Add Strong count
    let test_rc_2:Rc = Rc::clone(&test_rc);
    assert_eq!(2,Rc::strong_count(&test_rc));// ++
    assert_eq!(0,Rc::weak_count(&test_rc));
    
    // Add Weak count
    let mut test_weak:Weak = Rc::downgrade(&test_rc);
    assert_eq!(2,Weak::strong_count(&test_weak));// это из-за Rc
    assert_eq!(1,Weak::weak_count(&test_weak));// ++
        
    // Получение не изменяемого указателя *const T 
    {
        let ptr:*const Test = test_weak.as_ptr();
        let test:&Test = unsafe { &*ptr };
        assert_eq!(test.0,"gfg".to_string());        
    }
    // Получение не изменяемого указателя *const T 
    {   
        let raw:*const Test = test_weak.into_raw();
        let test:&Test = unsafe { &*raw };
        assert_eq!(test.0,"gfg".to_string());
        assert_eq!(1,Rc::weak_count(&test_rc)); // по прежнему 1 weak count
        test_weak = unsafe { Weak::from_raw(raw)};// восстановление 
        assert_eq!(1,Rc::weak_count(&test_rc)); // по прежнему 1 weak count
    }
    // Изменение данных
    let test_rc_3: Option> = test_weak.upgrade();
    if let Some(ref mut test_rc_3) = test_weak.upgrade(){
        unsafe {
            let test:&mut Test = Rc::get_mut_unchecked(test_rc_3);
            test.set_value("gfg".to_string());
        }   
    }
    
    assert_eq!(3,Rc::strong_count(&test_rc));// ++
    drop(test_rc_3);
    assert_eq!(2,Rc::strong_count(&test_rc));// --

    std::mem::drop(test_rc);// или std::mem::drop(test_rc_2);
    assert_eq!(1,Rc::strong_count(&test_rc_2));// --
    assert_eq!(1,Rc::weak_count(&test_rc_2));
  
    // Add Strong count (через weak достать rc)
    let test_rc_3: Rc = test_weak.upgrade().expect("при условии Rc count > 0"); 
    println!("Weak strong_count={} weak_count={}",Weak::strong_count(&test_weak),Weak::weak_count(&test_weak));
    assert_eq!(2,Weak::strong_count(&test_weak));// ++
    assert_eq!(1,Weak::weak_count(&test_weak));
    println!("Rc strong_count={} weak_count={}",Rc::strong_count(&test_rc_3),Rc::weak_count(&test_rc_3));

    // После удаление последнего strong pointer все weak pointer удаляются 
    std::mem::drop(test_rc_2); 
    std::mem::drop(test_rc_3);
    println!("Weak strong_count={} weak_count={}",Weak::strong_count(&test_weak),Weak::weak_count(&test_weak));
    assert_eq!(0,Weak::strong_count(&test_weak));// --
    assert_eq!(0,Weak::weak_count(&test_weak));// --
}