2017-02-22 18 views
4

私は引数として&Anyをとるクロージャを返そうとしています。次のコードはコンパイラエラーを返します。非スカラーキャスト: `Box <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を期待する関数を呼び出すことができたでしょう - タイプセーフティを壊し、未定義の動作を引き起こしてしまいます。次の問題になる。この時点で

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) 
     } 
    ) 

これを修正するには、Anyをダウンキャストし、任意のエラーを処理するクロージャー(この例では、それは私がunwrapを使用panicれるように)でそれをラップすることができます明らかに:TypedSelectorはオリジナルのボックス付きクロージャー(select)を所有していますが、この新しいクロージャーにはアクセスする必要があります。 3つのRustの値を渡すための方法、およびなし作業などがあります:

  • 値で(移動)はselector値によってselfをとる(ひいてはプロセスでそれを破壊)しない限り動作しません
  • で不変&referenceFnMut
  • によって変更することができません&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'を使用するために新規参入を教えるために最善であるかもしれないものを知っています。結局何が間違っていたのかを診断します。 @MatthieuM。 –

+0

。良い点が更新されました。 –

関連する問題