作为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()
}
不幸的是,这没有帮助,我得到了同样的错误。我在这里做什么错了?
答案 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;
}
让我们按步骤进行分解:
callback.borrow().as_ref().unwrap().as_ref().unchecked_ref()
-现在您有了&RefCell<Option<Closure<FnMut()>>>
,这是问题的第一步。发生这种情况时,此中间值现在的生存期与Ref<Option<...>>
不同(确切地说,是次等的)。任何由此产生的都会继承这个较短的寿命。暂时将其命名为'a
'b
将此as_ref
转换为Ref
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提供了一个示例,其中RefCell
和RefCell
类型被Function
替换(因为Closure
无法导入沙箱)。
答案 1 :(得分:1)
尽管我真的很喜欢Sébastien的回答和解释,但最终还是出于Ömer的建议,使用了一个宏,只是为了简洁。我将发布该宏,以防其他人使用该宏。
macro_rules! callback_to_function {
($callback:expr) => {
$callback
.borrow()
.as_ref()
.unwrap()
.as_ref()
.unchecked_ref()
};
}
我将塞巴斯蒂安的答案作为公认的答案,因为我认为这是解决此问题的更“正确”的方式,他提供了很好的解释。