casting - 非标量转换 : `Box<FnMut<&Any>>`

标签 casting rust traits

我正在尝试返回一个以 &Any 作为参数的闭包。以下代码返回编译器错误。

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 中有三种传递值的方法,但没有一种是按原样工作的:

  • 按值(移动)将不起作用,除非 selector需要 self按值(value)(因此在此过程中销毁它)
  • 通过不可变 &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)>
}

( Playground link )

关于casting - 非标量转换 : `Box<FnMut<&Any>>` ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42402632/

相关文章:

ios - 如何确定 iOS (id) 对象的结构?

java - java 中的原始数据类型转换 - 内部逻辑

ios - Swift:从 String 创建 double 型将 0000000000001 附加到结果数

tree - Rust 中二叉树的左旋转无法比原始树长

rust - 使用闭包从 Option<&T> 获取原始指针是否安全?

scala - 关于蛋糕图案的问题

scala - 构造函数(特征)不能应用于(类扩展特征)

C# 将 List<ObjBase> 转换为 List<Obj>

rust - 如何使用(不安全的)别名?

scala - 使用多重继承从Scala中的不同特征调用不同的方法