如何创建一个返回借入值的函数?

时间:2018-12-28 21:06:11

标签: rust wasm-bindgen

作为Rust WASM应用程序的一部分,我具有以下功能,可将Box ed闭包转换为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()
}

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

2 个答案:

答案 0 :(得分:1)

是的,这行不通。

  monthDiff(d1: Date, d2: Date): number {
    let months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth() + 1;
    months += d2.getMonth();
    return months <= 0 ? 0 : months;
  }

让我们按步骤进行分解:

  1. 您要借用callback.borrow().as_ref().unwrap().as_ref().unchecked_ref() -现在您有了&RefCell<Option<Closure<FnMut()>>>,这是问题的第一步。发生这种情况时,此中间值现在的生存期与Ref<Option<...>>不同(确切地说,是次等的)。任何由此产生的都会继承这个较短的寿命。暂时将其命名为'a
  2. 然后您'b将此as_ref转换为Ref
  3. 然后,Rust将Option<&'b Closure<FnMut()>>转换为&'b Closure<FnMut()>

第1步是发生突袭的地方。由于生命周期的冲突,您一头雾水。一种解决以下结构的半体面的方法:

&'b Function

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

定义了一个新的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() } } struct,其中包含对CC的{​​{1}}引用(其中您所用的'a泛型最终将是{{ 1}})和一个Rc<RefCell<T>>T的生命周期为Option<Closure<FnMut()>>的{​​{1}}到Ref,它们会自动填充到T构造函数中。

生成此对象的那一刻,您将拥有一个'a,其生存期与作为参数给出的ref的生存期相同,从而使整个问题不再存在。从那里,您可以调用from_callback来检索对您的内部类型的Ref引用。

这有一个陷阱:只要存在这些对象的一个,您(显然)将无法to_function &'a可能会也可能不会杀死您的用例(因为一个人不用borrow_mut()来取乐)。不过,这些对象的实例化相对便宜,因此一旦完成处理,您就可以将它们进行装箱。

here提供了一个示例,其中RefCellRefCell类型被Function替换(因为Closure无法导入沙箱)。

答案 1 :(得分:1)

尽管我真的很喜欢Sébastien的回答和解释,但最终还是出于Ömer的建议,使用了一个宏,只是为了简洁。我将发布该宏,以防其他人使用该宏。

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

我将塞巴斯蒂安的答案作为公认的答案,因为我认为这是解决此问题的更“正确”的方式,他提供了很好的解释。