2017-02-22 23 views
4

我试图返回一个以&Any作为参数的方法。以下代码返回编译器错误。非标量演员:`方块<FnMut<&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)> 
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

我缺少某种类型的注解?

回答

4

这里有几个问题。

首先,您要做什么(从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),但是这个新的封口需要访问它。有三种方法来传递拉斯特值,没有工作的是:

  • 通过值(移动)将无法正常工作,除非通过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)> 
} 

Playground link

+0

我知道什么是'unwrap'是诱人的,但它可能是最好的教新人使用'expect'代替。它确实能够诊断出哪里出了问题。 –

+0

@MatthieuM。好点,更新。 –

相关问题