rust 为什么其中一个有效,另一个无效?

f1tvaqid  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(119)

我想在限定了作用域的线程池上下文中,使用scoped_thread_pool跨线程共享(和更改)mutable Vec

let ids_for_discard: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));

let scoped_outcome = self.threadpool.scoped(|scope| {
    // here I iterate through a Vec of objects...
    for text_doc_hit_obj in &self.handling_framework.text_doc_hit_objs_for_processing {
        // each thread will need its Arc clone...
        let ids_for_discard = Arc::clone(&ids_for_discard);
        scope.execute(move ||  {
            // this (above) closure MUST return "()"... so
            // I use an inner closure to capture errors efficiently, using the "?" operator several times
            let inner_closure = move || -> Result<(), Box<dyn std::error::Error>> {
                ...
                let id_string = text_doc_hit_obj._id.clone();
                // let _ = ids_for_discard.lock()?.push(id_string); // fails to compile
                let _ = ids_for_discard.lock().unwrap().push(id_string); // passes

字符串
.如果我使用match子句,它也会通过。
我使用上面的?运算符得到的错误是:

error[E0515]: cannot return value referencing local data `ids_for_discard`
   --> src\indexing_pool.rs:112:19
    |
112 | ...                   let _ = ids_for_discard.lock()?.push(id_string);
    |                               ----------------------^
    |                               |
    |                               returns a value referencing data owned by the current function
    |                               `ids_for_discard` is borrowed here


有人能解释一下为什么?在这里编译失败吗?我真的很难理解。我想知道是否有一个危险,即尝试pushErr.
NB这也失败了:

let id_string = text_doc_hit_obj._id.clone();
let mut vec = ids_for_discard.lock()?;
vec.push(id_string);


产品编号:error[E0515]: cannot return value referencing local data 'ids_for_discard'
同样,如果将?替换为unwrap(),则通过。
我看到Mutex::lock()的签名是pub fn lock(&self) -> LockResult<MutexGuard<'_, T>>
...而LockResultpub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;,难道Box<dyn std::error::Error>>无法捕捉到这种错误?

33qvvth1

33qvvth11#

PoisonError确实包含一个MutexGuard和一个对Arc<Mutex<..>>的引用,在你的例子中,Arc<Mutex<..>>是函数的局部变量,所以你不能返回对它的引用。你可以map_err来交换错误,它不包含对任何局部变量的引用:

use std::sync::Mutex;
fn err_on_mutex_poisoned() -> Result<(), Box<dyn std::error::Error>> {
    let x = Mutex::new(0);
    // x.lock()?; // doesn't work
    x.lock().map_err(|_| "failed")?; // works
    Ok(())
}

字符串

rryofs0p

rryofs0p2#

Mutex::lock返回一个LockResult,根据它的文档:
请注意,Err变量还携带了相关的保护,并且可以通过into_inner方法获取。
我不太确定在什么情况下使用锁是明智的,即使它中毒了,但结果是,即使是错误变量也包含锁保护,它引用互斥体,因此不能返回。
您可以将错误Map到其他类型,例如:

let _ = ids_for_discard.lock()
        .map_err(|_| /* some other error here */)?
        .push(id_string);

字符串

相关问题