2

我有以下函数作为 Rust WASM 应用程序的一部分,用于将Boxed 闭包转换为 JavaScript 函数的 Rust 表示。

use js_sys::Function;

type Callback = Rc<RefCell<Option<Closure<FnMut()>>>>;

fn to_function(callback: &Callback) -> &Function {
    callback.borrow().as_ref().unwrap().as_ref().unchecked_ref()
}

但是,编译器抱怨返回值使用了借来的值(通过 获得callback.borrow()),因此无法返回。

因此,我决定添加生命周期注释以通知编译器这个新引用应该与输入一样长。

use js_sys::Function;

type Callback = Rc<RefCell<Option<Closure<FnMut()>>>>;

fn to_function<'a>(callback: &'a Callback) -> &'a Function {
    callback.borrow().as_ref().unwrap().as_ref().unchecked_ref()
}

不幸的是,这没有帮助,我得到了同样的错误。我在这里做错了什么?

4

2 回答 2

2

是的,这行不通。

callback.borrow().as_ref().unwrap().as_ref().unchecked_ref()

让我们分步分解:

  1. 您正在借款&RefCell<Option<Closure<FnMut()>>>- 所以您现在拥有Ref<Option<...>>,这是您的问题的第 1 步。当这种情况发生时,这个中间值现在的生命周期与'a(准确地说是劣质的)不同。任何由此产生的东西都将继承这个较短的生命周期。'b暂时调用
  2. 你然后as_ref这个Ref,把它变成Option<&'b Closure<FnMut()>>
  3. Rust 然后转换&'b Closure<FnMut()>&'b Function

第 1 步是问题发生的地方。由于一生的冲突,你留下了这个烂摊子。解决它的一种半体面的方法是以下结构:

use std::rc::{Rc};
use std::cell::{RefCell, Ref};
use std::ops::Deref;

struct CC<'a, T> {
    inner: &'a Rc<RefCell<T>>,
    borrow: Ref<'a, T>
}

impl<'a, T> CC<'a, T> {
    pub fn from_callback(item:&'a Rc<RefCell<T>>) -> CC<'a, T> {
        CC {
            inner: item,
            borrow: item.borrow()
        }
    }
    pub fn to_function(&'a self) -> &'a T {
        self.borrow.deref()
    }
}

这有点笨拙,但它可能是最干净的方法。

定义了一个 new struct CC,其中包含一个'aref Rc<RefCell<T>>T在您的情况下,泛型最终会是Option<Closure<FnMut()>>)和一个ReftoT与生命周期,在构造函数'a上自动填充。from_callback

生成此对象的那一刻,您将拥有Ref与作为参数提供的 ref 相同的生命周期,从而使整个问题消失。从那里,您可以调用to_function以检索&'a对您的内部类型的引用。

有一个问题:只要这些对象中的一个存在,您将(显然)无法在borrow_mut()RefCell,这可能会或可能不会杀死您的用例(因为人们不会RefCell使用它)。尽管如此,这些对象的实例化成本相对较低,因此一旦完成它们,您就可以负担得起将它们装箱的费用。

此处Function提供了一个将和Closure类型替换为u8(因为js_sys无法导入沙箱)的示例。

于 2018-12-28T22:18:03.537 回答
1

尽管我真的很喜欢 Sébastien 的回答和解释,但为了简洁起见,我最终还是接受了 Ömer 的使用宏的建议。我会发布宏以防其他人使用。

macro_rules! callback_to_function {
  ($callback:expr) => {
    $callback
      .borrow()
      .as_ref()
      .unwrap()
      .as_ref()
      .unchecked_ref()
  };
}

我会将 Sébastien 的答案作为已接受的答案,因为我相信这是解决此问题的更“正确”的方法,并且他提供了很好的解释。

于 2018-12-29T13:33:27.703 回答