无法将不可变的 'Box' 内容作为可变内容借用

3
我尝试通过静态变量在C回调中提供闭包。我已经能够使用 Fn 类型使其正常运行,但我想通过 FnMut 使其更加灵活,以便为库的用户提供更多选择。
以下是我的代码:
lazy_static! {
    static ref CALLBACK: Mutex<RefCell<Box<FnMut(Result<&str>) + Send>>> = Mutex::new(RefCell::new(Box::new(|_|())));
}

fn wrap_cb<F: Fn(Result<&str>)>(f: Option<F>) -> Option<unsafe extern "C" fn(*mut c_char, size_t)> {
    match f {
        Some(_) => {
            unsafe extern "C" fn wrapped(msg: *mut c_char, len: size_t) {
                let s = std::str::from_utf8(std::slice::from_raw_parts(msg as *const u8, len))
                    .map_err(Error::from);
                let x = CALLBACK.lock().unwrap();
                x.borrow_mut()(s);
            }
            Some(wrapped)
        }
        None => None,
    }
}

这会产生错误:

error[E0596]: cannot borrow immutable `Box` content as mutable
  --> src/wpactrl.rs:56:17
   |
56 |                 x.borrow_mut()(s);
   |                 ^^^^^^^^^^^^^^ cannot borrow as mutable
1个回答

2

看起来“无法将不可变Box内容借用为可变”问题简化为:

fn invoke(m: &Mutex<RefCell<Box<FnMut()>>>) {
    let r = m.lock().unwrap();
    r.borrow_mut()();
}

我还没有弄清楚为什么这样可以,但如果改成以下方式,它确实可以工作:

fn invoke(m: &Mutex<RefCell<Box<FnMut()>>>) {
    let r = m.lock().unwrap();
    let f = &mut *r.borrow_mut();
    f();
}

1
使用std::ops::DerefMut,然后执行x.borrow_mut().deref_mut()也可以工作。我猜这是因为borrow_mut()的返回类型是RefMut,但我不明白为什么它抱怨Box对象而不是RefMut<Box<_>>。看起来像是一个误导性的错误。 - spease
1
Box<FnMut()> 不能直接调用。您需要将其转换为 &mut FnMut() - aSpex
这里实际上不需要 RefCell。你可以使用 (&mut *r)() 来调用闭包。 - aSpex

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