从这个角度看,C++共享的Rust等价物是什么?

从这个角度看,C++共享的Rust等价物是什么?,rust,Rust,我有一个对象,我知道它在一个弧内,因为所有的实例都是弧。我希望能够在函数调用中传递我自己的克隆弧。我正在调用的东西稍后将在其他线程上调用我 C++中有一个标准的混合函数,叫做Enable SythDyRoFuxx。它使我能够做到这一点 类总线:public std::从\u中启用\u共享\u { .... 无效设置设备设备,。。。 { 设备->从该设备连接共享的设备; } } 如果此对象不在SyrdPPTR管理之下,最接近的C++必须在运行时失败,则在运行时失败。 我找不到对等的 编辑: 下面

我有一个对象,我知道它在一个弧内,因为所有的实例都是弧。我希望能够在函数调用中传递我自己的克隆弧。我正在调用的东西稍后将在其他线程上调用我

C++中有一个标准的混合函数,叫做Enable SythDyRoFuxx。它使我能够做到这一点

类总线:public std::从\u中启用\u共享\u { .... 无效设置设备设备,。。。 { 设备->从该设备连接共享的设备; } }

如果此对象不在SyrdPPTR管理之下,最接近的C++必须在运行时失败,则在运行时失败。 我找不到对等的

编辑:

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

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();
}

没有办法从一个&self转到存储self的弧。这是因为:

生锈引用与C++引用相比有更多的假设,这些引用会导致这种转换未定义行为。 Rust对Arc的实现甚至没有公开确定自身是否存储在Arc中所需的信息。 幸运的是,有另一种方法。不要为弧内的值创建一个&self并将其传递给方法,而是将弧直接传递给需要访问它的方法。您可以这样做:

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);
    }
}

然后,只能对封装在Arc中的共享字段调用print_field函数。

无法从&self转到存储self的Arc。这是因为:

生锈引用与C++引用相比有更多的假设,这些引用会导致这种转换未定义行为。 Rust对Arc的实现甚至没有公开确定自身是否存储在Arc中所需的信息。 幸运的是,有另一种方法。不要为弧内的值创建一个&self并将其传递给方法,而是将弧直接传递给需要访问它的方法。您可以这样做:

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);
    }
}

然后,print_field函数只能在封装在Arc中的共享文件上调用。

最近几天,我发现我需要这三次,于是决定停止尝试其他设计。就生锈而言,可能是糟糕的数据设计,但我需要它

通过更改类型的新函数来工作,使用该函数返回圆弧而不是原始自组织。我所有的对象都是弧形的,在它们被调用方弧形之前,现在是强制的

名为mekeeper的迷你util库

use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};


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!(),
        }
    }
}
使用它

pub struct Test {
    me: MeKeeper<Self>,
    foo:i8,
}

impl Test {
    pub fn new() -> Arc<Self> {
        let arc = Arc::new(Test {
            me: MeKeeper::new(),
            foo:42
        });
        arc.me.save(&arc);
        arc
    }
}
现在,当一个Test实例想要调用一个要求它通过圆弧的函数时,它会:

 fn nargle(){
     let me = me.get();
     Ooddle::fertang(me,42);// fertang needs an Arc<T>
 }
弱用途是共享的_from_this所做的,为了防止refcount死锁,我偷了这个想法


不可访问的路径是安全的,因为唯一可以调用MeKeeper::get的地方是这里拥有它的T Test实例,并且只有在T实例处于活动状态时才能进行调用。因此,弱::升级没有任何回报

最近几天,我发现我需要这三次,我决定停止尝试提出其他设计。就生锈而言,可能是糟糕的数据设计,但我需要它

通过更改类型的新函数来工作,使用该函数返回圆弧而不是原始自组织。我所有的对象都是弧形的,在它们被调用方弧形之前,现在是强制的

名为mekeeper的迷你util库

use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};


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!(),
        }
    }
}
使用它

pub struct Test {
    me: MeKeeper<Self>,
    foo:i8,
}

impl Test {
    pub fn new() -> Arc<Self> {
        let arc = Arc::new(Test {
            me: MeKeeper::new(),
            foo:42
        });
        arc.me.save(&arc);
        arc
    }
}
现在,当一个Test实例想要调用一个要求它通过圆弧的函数时,它会:

 fn nargle(){
     let me = me.get();
     Ooddle::fertang(me,42);// fertang needs an Arc<T>
 }
弱用途是共享的_from_this所做的,为了防止refcount死锁,我偷了这个想法


不可访问的路径是安全的,因为唯一可以调用MeKeeper::get的地方是这里拥有它的T Test实例,并且只有在T实例处于活动状态时才能进行调用。因此,弱::upgrade没有任何返回

有什么理由不简单地将您的类型定义为一个用一些私有状态封装弧的结构吗?@apetranzilla嗯,我认为我有一个很好的数据设计,尽管我在大规模的生锈学习曲线上。我有一个弧形的公共对象,在内部,它的所有数据都在一个静音的私有内部。我不想传递我的内部数据,因为这是一个实现细节。不管怎样,我想出了办法。让我的新FN构建ARC并窃取它的副本,以便以后使用,这就是C++ MIXIN的原因,这是C++中的Enable SydRayFuxx的主要原因,据我所知,它是能够在其中隐含的方法内访问SyrdypTR的。Rust允许方法将self作为弧或&弧,正如Alice的回答所显示的那样,所以这个特性实际上不是必需的。至少,我找不到在C++中使用它的例子,在那里我实际上是必要的。
n锈;也许你还有别的想法。@trentcl Arc就是这种类型,它仍然不能让我找到指向我的Arc。我需要将自己传递给一个函数,以便稍后可以调用我。我不能通过一个原始的“自我”,我必须通过指向我的弧线。我会编辑这个问题来展示我的想法,谢谢你提供了一个例子。使用我对Alice答案的变体。有什么理由不简单地将您的类型定义为一个用私有状态封装弧的结构吗?@apetranzilla嗯,我认为我的数据设计很好,尽管我在大量的生锈学习曲线上。我有一个弧形的公共对象,在内部,它的所有数据都在一个静音的私有内部。我不想传递我的内部数据,因为这是一个实现细节。不管怎样,我想出了办法。让我的新FN构建ARC并窃取它的副本,以便以后使用,这就是C++ MIXIN的原因,这是C++中的Enable SydRayFuxx的主要原因,据我所知,它是能够在其中隐含的方法内访问SyrdypTR的。Rust允许方法将self作为弧或&弧,正如Alice的回答所显示的那样,所以这个特性实际上不是必需的。至少,我找不到在C++中使用它的例子,在那里它实际上是必要的;也许你还有别的想法。@trentcl Arc就是这种类型,它仍然不能让我找到指向我的Arc。我需要将自己传递给一个函数,以便稍后可以调用我。我不能通过一个原始的“自我”,我必须通过指向我的弧线。我会编辑这个问题来展示我的想法,谢谢你提供了一个例子。使用Alice's answer.self:&Arc上的我的变体也很有用,特别是如果该方法并不总是需要克隆的话。权衡是额外的一层间接性。这不是我想要做的。使用你的名字。我有一个共享的实例,它已经弧了,从共享的一个方法,我想把我自己的弧传递给一个函数。在你的例子中,有人必须在我的弧上调用print_字段。是谁在做这件事?电话不可能从a&T转到它所存储的弧。这种转换只能走一条路。我的建议是永远不要丢掉你一开始需要的弧线。@pm100嗯,这不是我的建议。你的回答中的解决方案对我来说似乎不合理,因为如果纳格尔真的需要将一个弧传递给费尔唐,那么纳格尔本身应该被宣布为接受弧,或者可能是&Arc。相反,你在撒谎说nargle拿走了&self,并编写附带代码来掩盖谎言。在C++中,有时你必须撒谎,因为这只能是指针,所以SydRyFasux是解决方案。在《铁锈》中,你不必撒谎,那么为什么不让nargle显式地取弧呢?我也不知道一个自我实例如何从一个你不知道的自我方法中得到一个弧。您可以使另一个方法也采用Arc。self:&Arc也很有用,特别是当该方法不总是需要克隆时。权衡是额外的一层间接性。这不是我想要做的。使用你的名字。我有一个共享的实例,它已经弧了,从共享的一个方法,我想把我自己的弧传递给一个函数。在你的例子中,有人必须在我的弧上调用print_字段。是谁在做这件事?电话不可能从a&T转到它所存储的弧。这种转换只能走一条路。我的建议是永远不要丢掉你一开始需要的弧线。@pm100嗯,这不是我的建议。你的回答中的解决方案对我来说似乎不合理,因为如果纳格尔真的需要将一个弧传递给费尔唐,那么纳格尔本身应该被宣布为接受弧,或者可能是&Arc。相反,你在撒谎说nargle拿走了&self,并编写附带代码来掩盖谎言。在C++中,有时你必须撒谎,因为这只能是指针,所以SydRyFasux是解决方案。在《铁锈》中,你不必撒谎,那么为什么不让nargle显式地取弧呢?我也不知道一个自我实例如何从一个你不知道的自我方法中得到一个弧。你可以让另一种方法也采用圆弧。