2

特性に連鎖可能な変換を行おうとしていますが、いくつか問題があります。

次の形式の変換関数がたくさんあります。

fn transform<T: MyTrait>(in: T) -> impl MyTrait

そして、chain私ができるようにする機能が欲しい

let mut val: Box<MyTrait> = ...;
val = chain(val, transform1);
val = chain(val, transform2);
...

私はこの関数を書きました

fn chain<T, U, F>(val: Box<T>, f: F) -> Box<MyTrait>
  where T: MyTrait,
        U: MyTrait,
        F: FnOnce(T) -> U {
  Box::new(f(*val))
}

しかし、コンパイルすると、借用チェッカーは、型パラメーター U が十分に長く存続していないことを教えてくれます。私は自分の特性境界が私が望むものであると確信しており、ライフタイム指定子でさまざまなことを試したので、行き詰まっています:(

PS:chain関数をジェネリックにすることは可能MyTraitですか? 私はそれが可能だとは思いませんが、私たちは決して知りません...

編集

@chris-emerson が提案した修正を彼の回答に追加しました。コメントで述べたように、解決できないと思われる別の問題を発見しました。

この投稿を混乱させないように、コードの要点を次に示します。

要するに、問題は次のとおりです。チェーン関数はBox<T>オブジェクトを逆参照Tし、を変換関数に渡すT必要があるため、 Sized. しかし、この関数の要点は、任意の (コンパイル時には不明な)MyTrait実装を使用できるようにすることでした。例えば:

let mut val: Box<MyTrait> = ...;
//here we can know the type inside the Box
if ... {
  val = chain(val, transform);
}
//but here we don't know anymore
//(its either the original type,
//or the type returned by transform)

したがって、変換関数が &T または &mut T を受け取ることができない限り、この設計は機能しません (出力を生成するために入力を消費する必要があるため、これはできません)。

4

1 に答える 1

2

完全なコンパイラ メッセージは次のとおりです。

error[E0310]: the parameter type `U` may not live long enough
--> <anon>:7:3
  |
7 |   Box::new(f(*val))
  |   ^^^^^^^^^^^^^^^^^
  |
  = help: consider adding an explicit lifetime bound `U: 'static`...
  note:...so that the type `U` will meet its required lifetime bounds
--> <anon>:7:3
  |
7 |   Box::new(f(*val))
  |   ^^^^^^^^^^^^^^^^^

error: aborting due to previous error

コンパイラは、それが存続Uする必要があると言っています。'staticこれが実際に意味することは、その中のすべての参照がその有効期間の間有効である必要があるということですBox。これは、(コンパイラーがここで知っている限り) 永久に存続できるためです。

したがって、修正は簡単です:の境界に追加'staticします:U

fn chain<T, U, F>(val: Box<T>, f: F) -> Box<MyTrait>
  where T: MyTrait,
        U: MyTrait + 'static,
        F: FnOnce(T) -> U,
{
    Box::new(f(*val))
}

余分な境界を追加するU: 'staticことも同等です。

于 2016-10-21T08:28:09.377 に答える