如何将一个元素推入Vec并继续使用它?

5
我将尝试向 Vec<T> 添加一个项目,调用一个函数并等待它。 我仍在理解所有权和借用规则。 我了解以下代码行不起作用:
pub async fn begin_session(&mut self, stream: TcpStream) {
    let session = Session::new(stream);
    self.sessions.push(session);
            
    session.start_receiver().await; // obviously, won't work
}

下面是我想出的解决方案,但在我看来似乎不太理想(或线程安全):
pub async fn begin_session(&mut self, stream: TcpStream) {
    let session = Session::new(stream);
    self.sessions.push(session);

    let session = self.sessions.last().unwrap();
    
    session.start_receiver().await; // That works.
}

Vec<T> 中是否有一个函数可以执行 push(T) 并返回 T 呢?


1
如果会话是可克隆的,您可以执行以下操作:self.sessions.push(session.clone()); - Deedee Megadoodoo
Safe Rust是线程安全的。在这种情况下,没有其他线程可以同时持有对self的可变引用,因此您可以确信在pushlast之间self.sessions不会改变。 - eggyal
@eggyal 免于数据竞争,但不具备线程安全性。 - Acorn
@Acorn:同意,我表达不够严谨;但是我认为这里的担忧是数据竞争? - eggyal
@eggyal 我认为是这样的。抱歉我过于追求精确。 我更喜欢这种措辞,以避免初学者认为没有其他类型的竞态条件、死锁等。 - Acorn
2个回答

5

对我而言,这似乎不太理想(或线程安全)

如果优化器没有意识到unwrap()总是成功的话,这可能不是理想的。

然而,在这里线程安全并不起作用:如果你计划在后面共享Vec或者Self,那么你必须想办法保证线程安全。

Vec中是否有一个函数可以执行push(T)并返回T

如果有,那么这个方法很可能会返回一个&T或者&mut T,如果需要的话你可以复制或者克隆。其他人可能更喜欢返回索引。根据具体的需求,有许多可能性。

无论对于你的项目来说哪种方式最好,记住你可以自己向Vec中添加这个方法。例如:

trait PushReturn<T> {
    fn push_return(&mut self, t: T) -> &mut T;
}

impl<T> PushReturn<T> for Vec<T> {
    fn push_return(&mut self, t: T) -> &mut T {
        self.push(t);
        self.last_mut().unwrap()
    }
}

1

这似乎是一个很好的案例,可以使用引用计数对象,以 std::rc::Rc 的形式。

你的代码可能会看起来像这样:

pub async fn begin_session(&mut self, stream: TcpStream) {
    let session = Rc::new(Session::new(stream));
    self.sessions.push(Rc::clone(&session));

    &session.start_receiver().await;
}

当您克隆一个 Rc 时,您只是克隆了指向对象的引用,并增加了引用计数。您并没有克隆对象本身。
免责声明:我也正在学习 Rust。最好再听取第二个意见。

这会增加一些运行时开销,在 OP 的情况下可能并不必要。 - eggyal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接