非标量转换:`Box<FnMut<&Any>>`
Non-scalar cast: `Box<FnMut<&Any>>`
我正在尝试 return 一个以 &Any
作为参数的闭包。以下代码 return 是编译器错误。
trait Selector {
fn id(&self) -> i64;
fn selector(&self) -> Box<FnMut(&Any, &mut Any)>;
}
struct TypedSelector<TSource, TTarget> {
id: i64,
select: Box<FnMut(&TSource, &mut TTarget)>,
}
impl<TSource, TTarget> Selector for TypedSelector<TSource, TTarget>
where TSource: 'static,
TTarget: 'static
{
fn id(&self) -> i64 {
self.id
}
fn selector(&self) -> Box<FnMut(&Any, &mut Any)> {
self.select as Box<FnMut(&Any, &mut Any)>
}
}
编译错误如下:
error: non-scalar cast: `Box<for<'r, 'r> std::ops::FnMut(&'r TSource, &'r mut TTarget) + 'static>` as `Box<for<'r, 'r> std::ops::FnMut(&'r std::any::Any + 'static, &'r mut std::any::Any + 'static)>`
--> src\main.rs:190:9
|
190 | self.select as Box<FnMut(&Any, &mut Any)>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我是否遗漏了一些类型注释?
这里有一些问题。
首先,您尝试执行的操作(从 FnMut<&TSource, &mut TTarget>
转换为 FnMut<&Any, &mut Any>
)无效。如果你成功了,你将能够调用一个函数,期望 &TSource
具有不同的类型 - 所以你会破坏类型安全并导致未定义的行为。
要解决这个问题,您可以将它包装在一个闭包中,该闭包向下转换 Any
并处理任何错误(在本例中它将 panic
我使用 unwrap
):
Box::new(
move |a, b| {
let a = a.downcast_ref().expect("a was the wrong type.");
let b = b.downcast_mut().expect("b was the wrong type.");
(self.select)(a, b)
}
)
此时下一个问题变得明显:TypedSelector
拥有原始盒装闭包 (select
),但这个新闭包需要访问它。在 Rust 中有三种传递值的方法,none 按原样工作:
- 按值(移动)将不起作用,除非
selector
按值采用 self
(并因此在过程中销毁它)
- 不可变
&reference
不允许您调用 FnMut
- 通过可变的
&mut reference
同样不能从不可变的 &self
中完成。
所以有些事情需要改变。我将任意选择功能最齐全但重量级的选项,并使用 Rc<RefCell<T>>
共享指向内部可变 FnMut
的引用计数指针;这可能不是最适合您情况的选项:
fn selector(&self) -> Box<FnMut(&Any, &mut Any)+'static> {
let wrapped = self.select.clone();
Box::new(
move |a, b| {
let a = a.downcast_ref().expect("a was the wrong type.");
let b = b.downcast_mut().expect("b was the wrong type.");
// Mutably borrow the shared closure (checked at runtime)
let mut f = wrapped.borrow_mut();
(&mut *f)(a, b)
}
)
//self.select as Box<FnMut(&Any, &mut Any)>
}
我正在尝试 return 一个以 &Any
作为参数的闭包。以下代码 return 是编译器错误。
trait Selector {
fn id(&self) -> i64;
fn selector(&self) -> Box<FnMut(&Any, &mut Any)>;
}
struct TypedSelector<TSource, TTarget> {
id: i64,
select: Box<FnMut(&TSource, &mut TTarget)>,
}
impl<TSource, TTarget> Selector for TypedSelector<TSource, TTarget>
where TSource: 'static,
TTarget: 'static
{
fn id(&self) -> i64 {
self.id
}
fn selector(&self) -> Box<FnMut(&Any, &mut Any)> {
self.select as Box<FnMut(&Any, &mut Any)>
}
}
编译错误如下:
error: non-scalar cast: `Box<for<'r, 'r> std::ops::FnMut(&'r TSource, &'r mut TTarget) + 'static>` as `Box<for<'r, 'r> std::ops::FnMut(&'r std::any::Any + 'static, &'r mut std::any::Any + 'static)>`
--> src\main.rs:190:9
|
190 | self.select as Box<FnMut(&Any, &mut Any)>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我是否遗漏了一些类型注释?
这里有一些问题。
首先,您尝试执行的操作(从 FnMut<&TSource, &mut TTarget>
转换为 FnMut<&Any, &mut Any>
)无效。如果你成功了,你将能够调用一个函数,期望 &TSource
具有不同的类型 - 所以你会破坏类型安全并导致未定义的行为。
要解决这个问题,您可以将它包装在一个闭包中,该闭包向下转换 Any
并处理任何错误(在本例中它将 panic
我使用 unwrap
):
Box::new(
move |a, b| {
let a = a.downcast_ref().expect("a was the wrong type.");
let b = b.downcast_mut().expect("b was the wrong type.");
(self.select)(a, b)
}
)
此时下一个问题变得明显:TypedSelector
拥有原始盒装闭包 (select
),但这个新闭包需要访问它。在 Rust 中有三种传递值的方法,none 按原样工作:
- 按值(移动)将不起作用,除非
selector
按值采用self
(并因此在过程中销毁它) - 不可变
&reference
不允许您调用FnMut
- 通过可变的
&mut reference
同样不能从不可变的&self
中完成。
所以有些事情需要改变。我将任意选择功能最齐全但重量级的选项,并使用 Rc<RefCell<T>>
共享指向内部可变 FnMut
的引用计数指针;这可能不是最适合您情况的选项:
fn selector(&self) -> Box<FnMut(&Any, &mut Any)+'static> {
let wrapped = self.select.clone();
Box::new(
move |a, b| {
let a = a.downcast_ref().expect("a was the wrong type.");
let b = b.downcast_mut().expect("b was the wrong type.");
// Mutably borrow the shared closure (checked at runtime)
let mut f = wrapped.borrow_mut();
(&mut *f)(a, b)
}
)
//self.select as Box<FnMut(&Any, &mut Any)>
}