-1

我想SomeType取出Result<Vec<Data<&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没有正确地取得所有权。尽管实现Copytrait onSomeType可以消除错误,但我不确定是否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
        }
    }
}
4

1 回答 1

1

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

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

但是两者都mem::replace()需要Option::take()一个可变引用,而你所拥有的只是一个共享引用。要解决这个问题,您还需要使用内部可变性,例如由RefCell. 然后您将输入的类型DataRefCell<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();
    }
}
于 2021-09-24T20:19:58.007 回答