1

のようFnな特性は複数回実装できるため、これを行うことはできません。

trait Callable {
    fn call_me(&self);
}

impl<F, T> Callable for F
where
    F: Fn(T),
    T: Default,
{
    fn call_me(&self) {
        self(T::default())
    }
}

このようなことをしたいので、特性を実装できる特性オブジェクトを使用してみました。

impl<T> Callable for dyn Fn(T)
where
    T: Default,
{
    fn call_me(&self, _: &Env) {
        self(T::default())
    }
}

これは機能しますが、コールバック システム用にすべての種類を保存したいと考えてCallableいます。私の最初の最善の試みは a を使用するVec<Box<dyn Callable>>ことでしたが、特性オブジェクトを実装する特性の特性オブジェクトに変換できないようです。

trait Callable {
    fn call_me(&self);
}

impl<T> Callable for dyn Fn(T)
where
    T: Default,
{
    fn call_me(&self) {
        self(T::default())
    }
}

impl<T> Callable for &dyn Fn(T)
where
    T: Default,
{
    fn call_me(&self) {
        self(T::default())
    }
}

fn main() {
    let f = |n: i32| println!("n = {}", n);

    // fine, obviously
    f(i32::default());

    // also fine
    let bf = Box::new(f) as Box<dyn Fn(i32)>;
    bf(i32::default());

    // works if Callback implemented for &dyn Fn(T)
    // but only works on references now
    let bfc = &bf.as_ref() as &dyn Callable;
    bfc.call_me();

    // does not work
    let callbacks: Vec<Box<dyn Callable>> = vec![bf as Box<dyn Callable>];
}

これは私に与えます:

error[E0605]: non-primitive cast: `std::boxed::Box<dyn std::ops::Fn(i32)>` as `std::boxed::Box<dyn Callable>`
  --> src/main.rs:39:50
   |
39 |     let callbacks: Vec<Box<dyn Callable>> = vec![bf as Box<dyn Callable>];
   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object

理解できない。特性オブジェクトは型です。私CallableはすべてのFn(T)特性オブジェクトに対して を実装しました。通常、特定の実装された特性オブジェクトから強制できます。

  • なぜ機能しないのですか?
  • 回避策はありますか?
  • Fn特性パラメーターの型が一般的で関連付けられていない理由はありますか?

サイドノート

パラメーターの数とタイプに関係なく、環境からパラメーターをフェッチできるクロージャー (関数だけでなく) を格納するために、この種のシステムが必要です。

trait FromEnv {
    fn from_env(env: &Env) -> Self;
}

trait Callable {
    fn call_me(&self, env: &Env);
}

impl<T> Callable for Fn(T)
where
    T: FromEnv,
{
    fn call_me(&self, env: &Env) {
        self(T::from_env(env))
    }
}

// same kind of impl for Fn(T, U, ..., Z)

自分ができるということがわかっている:

  • &Envユーザーが「抽出」を処理できるようにするクロージャーを許可します。
  • マクロを使用して、直接実装する独自のカスタム クロージャ タイプを作成しますCallable
4

0 に答える 0