web-dev-qa-db-ja.com

TcpConnectionNewを使用すると、特性境界 `():futures :: Future`が満たされません

単純なTCP client in Rust using Tokio crate。私のコードは にかなり近い)を書き込もうとしています。この例 マイナスTLS:

extern crate futures;
extern crate tokio_core;
extern crate tokio_io;

use futures::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_io::io;

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let connection = TcpStream::connect(&"127.0.0.1:8080".parse().unwrap(), &handle);

    let server = connection.and_then(|stream| {
        io::write_all(stream, b"hello");
    });

    core.run(server).unwrap();
}

ただし、コンパイルは次のエラーで失敗します。

error[E0277]: the trait bound `(): futures::Future` is not satisfied
  --> src/main.rs:16:29
   |
16 |     let server = connection.and_then(|stream| {
   |                             ^^^^^^^^ the trait `futures::Future` is not implemented for `()`
   |
   = note: required because of the requirements on the impl of `futures::IntoFuture` for `()`

error[E0277]: the trait bound `(): futures::Future` is not satisfied
  --> src/main.rs:20:10
   |
20 |     core.run(server).unwrap();
   |          ^^^ the trait `futures::Future` is not implemented for `()`
   |
   = note: required because of the requirements on the impl of `futures::IntoFuture` for `()`

ドキュメント によると、実装する必要があるため、奇妙だと思います。

使っています

  • さび1.19.0
  • 先物0.1.16
  • tokio-core 0.1.10
  • tokio-io 0.1.3

何が足りないのですか?

8
Sergey

TL; DR:_io::write_all_の後のセミコロンを削除します。


_and_then_ の定義を確認してください:

_fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F> 
where
    F: FnOnce(Self::Item) -> B,
    B: IntoFuture<Error = Self::Error>,
    Self: Sized, 
_

クロージャ(F)は、開始クロージャ(_B: IntoFuture_)と一致するエラータイプで将来(_Error = Self::Error_)に変換できるタイプ(B)を返す必要があります。

yourクロージャは何を返しますか? _()_。何故ですか?行の最後にセミコロン(_;_)を配置したためです。 _()_は 特性IntoFuture を実装しません。これは、「_futures::IntoFuture_ for _()_の実装のエラーメッセージ部分で示されます」:

_impl<F: Future> IntoFuture for F {
    type Future = F;
    type Item = F::Item;
    type Error = F::Error;
}
_

セミコロンを削除すると、_io::write_all_によって返されたFutureが_and_then_に戻され、プログラムがコンパイルされます。

一般に、先物は、それ自体が先物である小さなコンポーネントを組み合わせることによって機能します。これらすべてが連携して、本質的にステートマシンである単一の大きな未来を構築します。このようなコンビネータを使用する場合、ほとんどの場合、未来を返す必要があるため、これを覚えておくとよいでしょう。

12
Shepmaster

残念ながら、ここでの答えは非常に具体的ですが、質問は次のようなあらゆる種類の検索で発生します。

特性_futures::Future_は_()_には実装されていません

この種のエラーの典型的なシナリオは次のとおりです。

_foo.then(|stream| {
    // ... Do random things here
    final_statement();
});
_

拡張関数 の大部分はIntoFutureを実装するために戻り値の型を必要とするため、これによりエラーが発生します。ただし、_()_はIntoFutureを実装せず、ブロックを_;_で終了することにより、暗黙の戻り値の型は_()_になります。

ただし、IntoFutureisOptionおよびResult に実装されています。

セミコロンを漠然とラ​​ンダムに削除するのではなく、これによってコードが魔法のようにコンパイルされることを期待して、次のことを検討してください。

Futureを使用してIntoFutureに変換できるものを返す必要があります。

戻るという具体的な約束がない場合は、コールバックからOk(())を返して「これで完了です」と言うことを検討してください。

_foo.then(|stream| {
    // ... Do random things here
    final_statement();
    return Ok(()); // <-- Result(()) implements `IntoFuture`.
});
_

特に、このブロックを明示的なreturnステートメントで終了することに注意してください。これは意図的なものです。これは、「オブジェクトを暗黙的に返すためにセミコロンを省略できる」の人間工学が明らかに有害である方法の典型的な例です。 Ok(());でブロックを終了すると、同じエラーで失敗し続けます。

7
Doug