如何从Result<Vec<Data<&T>>>中取出T?

How to take T out of Result<Vec<Data<&T>>>?

我想从Result<Vec<Data<&SomeType>>>中取出SomeType,然后通过通道传递,但是我失败了:

pub fn read(result: Result<Vec<Data<&SomeType>>, ()>, tx: mpsc::Sender<SomeType>) {
    if let Ok(datas) = result {
        for data in datas.iter() {
            let actual_data = data.value();
            let some_type_instance = SomeType { k: 1 };
            tx.send(some_type_instance); // works
            tx.send(**actual_data); // errors
        }
    }
}

错误:

error[E0507]: cannot move out of `**actual_data` which is behind a shared reference
  --> src/main.rs:40:21
   |
40 |             tx.send(**actual_data);
   |                     ^^^^^^^^^^^^^ move occurs because `**actual_data` has type `SomeType`, which does not implement the `Copy` trait

似乎 tx 没有正确取得所有权。虽然在 SomeType 上实现 Copy 特性可以消除错误,但我不确定 CopyClone 是否会降低性能。我正在努力解决它,但找不到正确的方法来修复它。

以下是重现错误的完整代码

use std::result::Result;
use std::sync::mpsc;

pub struct SomeType {
    k: i32,
}

pub struct Data<D> {
    value: D,
}

impl<D> Data<D> {
    pub fn value(&self) -> &D {
        &self.value
    }
}

pub fn main() {
    let a = SomeType { k: 1 };
    let b = SomeType { k: 2 };
    let c = SomeType { k: 3 };

    let A = Data { value: &a };
    let B = Data { value: &b };
    let C = Data { value: &c };

    let datas = vec![A, B, C];

    let result = Ok(datas);
    let (tx, rx) = mpsc::channel();
    read(result, tx);
}

pub fn read(result: Result<Vec<Data<&SomeType>>, ()>, tx: mpsc::Sender<SomeType>) {
    if let Ok(datas) = result {
        for data in datas.iter() {
            let actual_data = data.value();
            let some_type_instance = SomeType { k: 1 };
            tx.send(some_type_instance); // this line works
            tx.send(**actual_data); // this line errors
        }
    }
}

当你只有一个 &T 时,如果不克隆引用后面的值,你将无法获得 T,因为提取非复制值会 移动 它,并且提供参考的 T(此处 Data)的所有者希望该值保持有效。

但是,如果您控制存储在 Data 中的类型,则可以将您的实际值包装在 Option 中。然后,您可以使用 std::mem::replace(ref_to_t, None) 获取引用后面的值,并将 None 留在原处。 Option 甚至有一个 take() 方法可以为您做到这一点。

但是 mem::replace()Option::take() 都需要一个可变引用,而你所拥有的只是一个共享引用。要解决这个问题,您还需要使用内部可变性,例如 RefCell 提供的。然后你将放入 Data 的类型是 RefCell<Option<SomeType>> - 不要被嵌套的泛型推迟,只需将它们读作“RefCell 包含一个可选的 SomeType” . RefCell 有一个 borrow_mut() 方法,为您提供对内部内容的可变引用,然后您可以在该方法上调用 Option::take(),或者您可以调用 RefCell::take(),这将做正确的事情自己。

pub fn main() {
    let a = SomeType { k: 1 };
    let b = SomeType { k: 2 };
    let c = SomeType { k: 3 };

    let da = Data {
        value: RefCell::new(Some(a)),
    };
    let db = Data {
        value: RefCell::new(Some(b)),
    };
    let dc = Data {
        value: RefCell::new(Some(c)),
    };

    let datas = vec![da, db, dc];

    let (tx, _rx) = mpsc::channel();
    read(&datas, tx);
}

pub fn read(datas: &[Data<RefCell<Option<SomeType>>>], tx: mpsc::Sender<SomeType>) {
    for data in datas {
        let actual_data = data.value().take().unwrap();
        tx.send(actual_data).unwrap();
    }
}