什么是 C++ 的 shared_from_this 的 Rust 等价物?

pm1*_*100 1 rust

我有一个对象,我知道它在 an 内部,Arc因为所有实例总是Arced。我希望能够Arc在函数调用中传递我自己的克隆。我正在调用的东西稍后会在其他线程上给我回电。

在 C++ 中,有一个标准的 mixin 叫做enable_shared_from_this. 它使我能够做到这一点

class Bus : public std::enable_shared_from_this<Bus>
{
....
   void SetupDevice(Device device,...)
   {
       device->Attach(shared_from_this());
   }
}
Run Code Online (Sandbox Code Playgroud)

如果此对象不受shared_ptr管理(最接近的 C++ 必须Arc),那么这将在运行时失败。

我找不到等价物。

编辑:

这是一个为什么需要它的例子。我有一个定时器队列库。它允许客户端请求在将来的某个时间点运行任意闭包。代码在专用线程上运行。要使用它,您必须传递要稍后执行的函数的闭包。

use std::time::{Duration, Instant};
use timerqueue::*;
use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};

// inline me keeper cos not on github
pub struct MeKeeper<T> {
    them: Mutex<Weak<T>>,
}

impl<T> MeKeeper<T> {
    pub fn new() -> Self {
        Self {
            them: Mutex::new(Weak::new()),
        }
    }
    pub fn save(&self, arc: &Arc<T>) {
        *self.them.lock().deref_mut() = Arc::downgrade(arc);
    }
    pub fn get(&self) -> Arc<T> {
        match self.them.lock().upgrade() {
            Some(arc) => return arc,
            None => unreachable!(),
        }
    }
}
// -----------------------------------

struct Test {
    data:String,
    me: MeKeeper<Self>,
}

impl Test {

    pub fn new() -> Arc<Test>{
        let arc = Arc::new(Self {
            me: MeKeeper::new(),
            data: "Yo".to_string()
        });
        arc.me.save(&arc);
        arc
    }
    
    fn task(&self) {
        println!("{}", self.data);
    }

    // in real use case the TQ and a ton of other status data is passed in the new call for Test
    // to keep things simple here the 'container' passes tq as an arg

    pub fn do_stuff(&self, tq: &TimerQueue) {
        // stuff includes a async task that must be done in 1 second

        //.....
        let me = self.me.get().clone();
        tq.queue(
            Box::new(move || me.task()),
            "x".to_string(),
            Instant::now() + Duration::from_millis(1000),
        );
    }


}

fn main() {
    // in real case (PDP11 emulator) there is a Bus class owning tons of objects thats
    // alive for the whole duration
    let tq = Arc::new(TimerQueue::new());
    let test = Test::new();
    test.do_stuff(&*tq);
    // just to keep everything alive while we wait
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
}
Run Code Online (Sandbox Code Playgroud)

货物 toml

[package]
name = "tqclient"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
timerqueue = { git = "https://github.com/pm100/timerqueue.git" }
parking_lot = "0.11"
Run Code Online (Sandbox Code Playgroud)

Ali*_*yhl 5

有没有办法从去&selfArc那个self被存储在。这是因为:

  1. 与 C++ 引用相比,Rust 引用有额外的假设,这会导致这种转换未定义行为。
  2. Rust 的实现Arc甚至没有公开确定是否self存储在Arc.

幸运的是,有一种替代方法。与其为&self中的值创建 aArc并将其传递给方法,不如Arc直接将传递给需要访问它的方法。你可以这样做:

use std::sync::Arc;

struct Shared {
    field: String,
}

impl Shared {
    fn print_field(self: Arc<Self>) {
        let clone: Arc<Shared> = self.clone();
        
        println!("{}", clone.field);
    }
}
Run Code Online (Sandbox Code Playgroud)

那么该print_field函数只能在Shared封装在Arc.

  • 从 `&amp;T` 到存储它的 `Arc&lt;T&gt;` 是不可能的。这种转换只能进行一种方式。我的建议是永远不要扔掉你最初需要的“Arc”。 (4认同)