単純な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 `()`
ドキュメント によると、実装する必要があるため、奇妙だと思います。
使っています
何が足りないのですか?
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
_に戻され、プログラムがコンパイルされます。
一般に、先物は、それ自体が先物である小さなコンポーネントを組み合わせることによって機能します。これらすべてが連携して、本質的にステートマシンである単一の大きな未来を構築します。このようなコンビネータを使用する場合、ほとんどの場合、未来を返す必要があるため、これを覚えておくとよいでしょう。
残念ながら、ここでの答えは非常に具体的ですが、質問は次のようなあらゆる種類の検索で発生します。
特性_
futures::Future
_は_()
_には実装されていません
この種のエラーの典型的なシナリオは次のとおりです。
_foo.then(|stream| {
// ... Do random things here
final_statement();
});
_
拡張関数 の大部分はIntoFuture
を実装するために戻り値の型を必要とするため、これによりエラーが発生します。ただし、_()
_はIntoFuture
を実装せず、ブロックを_;
_で終了することにより、暗黙の戻り値の型は_()
_になります。
ただし、IntoFuture
isは Option
およびResult
に実装されています。
セミコロンを漠然とランダムに削除するのではなく、これによってコードが魔法のようにコンパイルされることを期待して、次のことを検討してください。
Future
を使用してIntoFuture
に変換できるものを返す必要があります。
戻るという具体的な約束がない場合は、コールバックからOk(())
を返して「これで完了です」と言うことを検討してください。
_foo.then(|stream| {
// ... Do random things here
final_statement();
return Ok(()); // <-- Result(()) implements `IntoFuture`.
});
_
特に、このブロックを明示的なreturnステートメントで終了することに注意してください。これは意図的なものです。これは、「オブジェクトを暗黙的に返すためにセミコロンを省略できる」の人間工学が明らかに有害である方法の典型的な例です。 Ok(());
でブロックを終了すると、同じエラーで失敗し続けます。